ruby-saml 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
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
|