ruby-saml 0.4.1 → 0.4.2
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/VERSION +1 -1
 - data/lib/onelogin/saml/response.rb +22 -5
 - data/lib/xml_security.rb +14 -0
 - data/ruby-saml.gemspec +2 -2
 - data/test/ruby-saml_test.rb +20 -12
 - data/test/test_helper.rb +7 -0
 - metadata +4 -4
 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            0.4. 
     | 
| 
      
 1 
     | 
    
         
            +
            0.4.2
         
     | 
| 
         @@ -8,18 +8,20 @@ module Onelogin::Saml 
     | 
|
| 
       8 
8 
     | 
    
         
             
                DSIG      = "http://www.w3.org/2000/09/xmldsig#"
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
                attr_accessor :response, :document, :logger, :settings, :original
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_accessor :bypass_conditions_check # for testing only
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
13 
     | 
    
         
             
                def initialize(response)
         
     | 
| 
       13 
14 
     | 
    
         
             
                  raise ArgumentError.new("Response cannot be nil") if response.nil?
         
     | 
| 
       14 
     | 
    
         
            -
                  self. 
     | 
| 
       15 
     | 
    
         
            -
                  self. 
     | 
| 
       16 
     | 
    
         
            -
                  self. 
     | 
| 
      
 15 
     | 
    
         
            +
                  self.bypass_conditions_check  = false
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.response                 = response
         
     | 
| 
      
 17 
     | 
    
         
            +
                  self.document                 = XMLSecurity::SignedDocument.new(Base64.decode64(response))
         
     | 
| 
       17 
18 
     | 
    
         
             
                end
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
                def is_valid?
         
     | 
| 
       20 
21 
     | 
    
         
             
                  return false if response.empty?
         
     | 
| 
       21 
22 
     | 
    
         
             
                  return false if settings.nil?
         
     | 
| 
       22 
23 
     | 
    
         
             
                  return false if settings.idp_cert_fingerprint.nil?
         
     | 
| 
      
 24 
     | 
    
         
            +
                  return false if !check_conditions
         
     | 
| 
       23 
25 
     | 
    
         | 
| 
       24 
26 
     | 
    
         
             
                  document.validate(settings.idp_cert_fingerprint, logger)
         
     | 
| 
       25 
27 
     | 
    
         
             
                end
         
     | 
| 
         @@ -27,12 +29,21 @@ module Onelogin::Saml 
     | 
|
| 
       27 
29 
     | 
    
         
             
                # The value of the user identifier as designated by the initialization request response
         
     | 
| 
       28 
30 
     | 
    
         
             
                def name_id
         
     | 
| 
       29 
31 
     | 
    
         
             
                  @name_id ||= begin
         
     | 
| 
       30 
     | 
    
         
            -
                     
     | 
| 
       31 
     | 
    
         
            -
                    node  = REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{uri[1,uri.size]}']/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
         
     | 
| 
      
 32 
     | 
    
         
            +
                    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 
33 
     | 
    
         
             
                    node.text
         
     | 
| 
       33 
34 
     | 
    
         
             
                  end
         
     | 
| 
       34 
35 
     | 
    
         
             
                end
         
     | 
| 
       35 
36 
     | 
    
         | 
| 
      
 37 
     | 
    
         
            +
                def check_conditions
         
     | 
| 
      
 38 
     | 
    
         
            +
                  return true if self.bypass_conditions_check
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  cond_element = REXML::XPath.first(document,"/p:Response/a:Assertion[@ID='#{document.signed_element_id[1,document.signed_element_id.size]}']/a:Conditions", { "p" => PROTOCOL, "a" => ASSERTION })
         
     | 
| 
      
 41 
     | 
    
         
            +
                  return false unless cond_element
         
     | 
| 
      
 42 
     | 
    
         
            +
                  return false unless parseXsDateTime(cond_element.attribute('NotBefore').to_s) < Time.now.utc
         
     | 
| 
      
 43 
     | 
    
         
            +
                  return false unless parseXsDateTime(cond_element.attribute('NotOnOrAfter').to_s) >= Time.now.utc
         
     | 
| 
      
 44 
     | 
    
         
            +
                  true
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       36 
47 
     | 
    
         
             
                # A hash of alle the attributes with the response. Assuming there is only one value for each key
         
     | 
| 
       37 
48 
     | 
    
         
             
                def attributes
         
     | 
| 
       38 
49 
     | 
    
         
             
                  @attr_statements ||= begin
         
     | 
| 
         @@ -62,5 +73,11 @@ module Onelogin::Saml 
     | 
|
| 
       62 
73 
     | 
    
         
             
                  end
         
     | 
| 
       63 
74 
     | 
    
         
             
                end
         
     | 
| 
       64 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                private
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                def parseXsDateTime(xsDatetime)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  return nil unless xsDatetime =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/
         
     | 
| 
      
 80 
     | 
    
         
            +
                  Time.utc($1, $2, $3, $4, $5, $6)
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
       65 
82 
     | 
    
         
             
              end
         
     | 
| 
       66 
83 
     | 
    
         
             
            end
         
     | 
    
        data/lib/xml_security.rb
    CHANGED
    
    | 
         @@ -32,6 +32,14 @@ require "digest/sha1" 
     | 
|
| 
       32 
32 
     | 
    
         
             
            module XMLSecurity
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
              class SignedDocument < REXML::Document
         
     | 
| 
      
 35 
     | 
    
         
            +
                DSIG      = "http://www.w3.org/2000/09/xmldsig#"
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                attr_accessor :signed_element_id
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def initialize(response)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  super(response)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  extract_signed_element_id
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
       35 
43 
     | 
    
         | 
| 
       36 
44 
     | 
    
         
             
                def validate (idp_cert_fingerprint, logger = nil)
         
     | 
| 
       37 
45 
     | 
    
         
             
                  # get cert from response
         
     | 
| 
         @@ -87,5 +95,11 @@ module XMLSecurity 
     | 
|
| 
       87 
95 
     | 
    
         
             
                  return valid_flag
         
     | 
| 
       88 
96 
     | 
    
         
             
                end
         
     | 
| 
       89 
97 
     | 
    
         | 
| 
      
 98 
     | 
    
         
            +
                private
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                def extract_signed_element_id
         
     | 
| 
      
 101 
     | 
    
         
            +
                  reference_element       = REXML::XPath.first(self, "//ds:Signature/ds:SignedInfo/ds:Reference", {"ds"=>DSIG})
         
     | 
| 
      
 102 
     | 
    
         
            +
                  self.signed_element_id  = reference_element.attribute("URI").value unless reference_element.nil?
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
       90 
104 
     | 
    
         
             
              end
         
     | 
| 
       91 
105 
     | 
    
         
             
            end
         
     | 
    
        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.2"
         
     | 
| 
       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-04}
         
     | 
| 
       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 = [
         
     | 
    
        data/test/ruby-saml_test.rb
    CHANGED
    
    | 
         @@ -39,13 +39,11 @@ class RubySamlTest < Test::Unit::TestCase 
     | 
|
| 
       39 
39 
     | 
    
         
             
                  assert !response.name_id.nil?
         
     | 
| 
       40 
40 
     | 
    
         
             
                end
         
     | 
| 
       41 
41 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
                should " 
     | 
| 
       43 
     | 
    
         
            -
                  response = Onelogin::Saml::Response.new( 
     | 
| 
       44 
     | 
    
         
            -
                   
     | 
| 
       45 
     | 
    
         
            -
                  response 
     | 
| 
       46 
     | 
    
         
            -
                   
     | 
| 
       47 
     | 
    
         
            -
                  assert response.is_valid?
         
     | 
| 
       48 
     | 
    
         
            -
                  assert response.name_id == "test@onelogin.com"
         
     | 
| 
      
 42 
     | 
    
         
            +
                should "check time conditions" do
         
     | 
| 
      
 43 
     | 
    
         
            +
                  response = Onelogin::Saml::Response.new(response_document)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  assert !response.check_conditions
         
     | 
| 
      
 45 
     | 
    
         
            +
                  response = Onelogin::Saml::Response.new(response_document_5)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  assert response.check_conditions
         
     | 
| 
       49 
47 
     | 
    
         
             
                end
         
     | 
| 
       50 
48 
     | 
    
         | 
| 
       51 
49 
     | 
    
         
             
                context "#is_valid?" do
         
     | 
| 
         @@ -60,15 +58,25 @@ class RubySamlTest < Test::Unit::TestCase 
     | 
|
| 
       60 
58 
     | 
    
         
             
                  end
         
     | 
| 
       61 
59 
     | 
    
         | 
| 
       62 
60 
     | 
    
         
             
                  should "return true when the response is initialized with valid data" do
         
     | 
| 
       63 
     | 
    
         
            -
                    response = Onelogin::Saml::Response.new( 
     | 
| 
      
 61 
     | 
    
         
            +
                    response = Onelogin::Saml::Response.new(response_document_4)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    response.bypass_conditions_check = true
         
     | 
| 
      
 63 
     | 
    
         
            +
                    assert !response.is_valid?
         
     | 
| 
       64 
64 
     | 
    
         
             
                    settings = Onelogin::Saml::Settings.new
         
     | 
| 
       65 
     | 
    
         
            -
                     
     | 
| 
      
 65 
     | 
    
         
            +
                    assert !response.is_valid?
         
     | 
| 
       66 
66 
     | 
    
         
             
                    response.settings = settings
         
     | 
| 
       67 
67 
     | 
    
         
             
                    assert !response.is_valid?
         
     | 
| 
       68 
     | 
    
         
            -
                     
     | 
| 
       69 
     | 
    
         
            -
                     
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
      
 68 
     | 
    
         
            +
                    settings.idp_cert_fingerprint = signature_fingerprint_1
         
     | 
| 
      
 69 
     | 
    
         
            +
                    assert response.is_valid?
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  should "not allow signature wrapping attack" do
         
     | 
| 
      
 73 
     | 
    
         
            +
                    response = Onelogin::Saml::Response.new(response_document_4)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    response.bypass_conditions_check = true
         
     | 
| 
      
 75 
     | 
    
         
            +
                    settings = Onelogin::Saml::Settings.new
         
     | 
| 
      
 76 
     | 
    
         
            +
                    settings.idp_cert_fingerprint = signature_fingerprint_1
         
     | 
| 
      
 77 
     | 
    
         
            +
                    response.settings = settings
         
     | 
| 
       71 
78 
     | 
    
         
             
                    assert response.is_valid?
         
     | 
| 
      
 79 
     | 
    
         
            +
                    assert response.name_id == "test@onelogin.com"
         
     | 
| 
       72 
80 
     | 
    
         
             
                  end
         
     | 
| 
       73 
81 
     | 
    
         
             
                end
         
     | 
| 
       74 
82 
     | 
    
         | 
    
        data/test/test_helper.rb
    CHANGED
    
    | 
         @@ -24,6 +24,13 @@ class Test::Unit::TestCase 
     | 
|
| 
       24 
24 
     | 
    
         
             
                @response_document4 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response4.xml.base64'))
         
     | 
| 
       25 
25 
     | 
    
         
             
              end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
              def response_document_5
         
     | 
| 
      
 28 
     | 
    
         
            +
                doc = Base64.decode64(response_document)
         
     | 
| 
      
 29 
     | 
    
         
            +
                doc.gsub!(/NotBefore=\"(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z\"/, "NotBefore=\"#{(Time.now-300).getutc.strftime("%Y-%m-%dT%XZ")}\"")
         
     | 
| 
      
 30 
     | 
    
         
            +
                doc.gsub!(/NotOnOrAfter=\"(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z\"/, "NotOnOrAfter=\"#{(Time.now+300).getutc.strftime("%Y-%m-%dT%XZ")}\"")
         
     | 
| 
      
 31 
     | 
    
         
            +
                Base64.encode64(doc)
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
              
         
     | 
| 
       27 
34 
     | 
    
         
             
              def signature_fingerprint_1
         
     | 
| 
       28 
35 
     | 
    
         
             
                @signature_fingerprint1 ||= "C5:19:85:D9:47:F1:BE:57:08:20:25:05:08:46:EB:27:F6:CA:B7:83"
         
     | 
| 
       29 
36 
     | 
    
         
             
              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: 11
         
     | 
| 
       5 
5 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       6 
6 
     | 
    
         
             
              segments: 
         
     | 
| 
       7 
7 
     | 
    
         
             
              - 0
         
     | 
| 
       8 
8 
     | 
    
         
             
              - 4
         
     | 
| 
       9 
     | 
    
         
            -
              -  
     | 
| 
       10 
     | 
    
         
            -
              version: 0.4. 
     | 
| 
      
 9 
     | 
    
         
            +
              - 2
         
     | 
| 
      
 10 
     | 
    
         
            +
              version: 0.4.2
         
     | 
| 
       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-04 00:00:00 -06:00
         
     | 
| 
       19 
19 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       20 
20 
     | 
    
         
             
            dependencies: 
         
     | 
| 
       21 
21 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     |