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
|