Skip to content

Commit 7488f28

Browse files
author
Rob Fletcher
committed
Merge pull request #98 from onelogin/error_messages
Error reporting for diagnostics
2 parents 6e6a8ad + 327d4e1 commit 7488f28

4 files changed

Lines changed: 33 additions & 4 deletions

File tree

lib/onelogin/ruby-saml/response.rb

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ class Response
1313

1414
# TODO: This should probably be ctor initialized too... WDYT?
1515
attr_accessor :settings
16+
attr_accessor :errors
1617

1718
attr_reader :options
1819
attr_reader :response
1920
attr_reader :document
2021

2122
def initialize(response, options = {})
23+
@errors = []
2224
raise ArgumentError.new("Response cannot be nil") if response.nil?
2325
@options = options
2426
@response = (response =~ /^</) ? response : Base64.decode64(response)
25-
@document = XMLSecurity::SignedDocument.new(@response)
27+
@document = XMLSecurity::SignedDocument.new(@response, @errors)
2628
end
2729

2830
def is_valid?
@@ -33,6 +35,10 @@ def validate!
3335
validate(false)
3436
end
3537

38+
def errors
39+
@errors
40+
end
41+
3642
# The value of the user identifier as designated by the initialization request response
3743
def name_id
3844
@name_id ||= begin
@@ -153,9 +159,14 @@ def validate_structure(soft = true)
153159
@xml = Nokogiri::XML(self.document.to_s)
154160
end
155161
if soft
156-
@schema.validate(@xml).map{ return false }
162+
@schema.validate(@xml).map{
163+
@errors << "Schema validation failed";
164+
return false
165+
}
157166
else
158-
@schema.validate(@xml).map{ |error| validation_error("#{error.message}\n\n#{@xml.to_s}") }
167+
@schema.validate(@xml).map{ |error| @errors << "#{error.message}\n\n#{@xml.to_s}";
168+
validation_error("#{error.message}\n\n#{@xml.to_s}")
169+
}
159170
end
160171
end
161172

@@ -197,10 +208,12 @@ def validate_conditions(soft = true)
197208
now = Time.now.utc
198209

199210
if not_before && (now + (options[:allowed_clock_drift] || 0)) < not_before
211+
@errors << "Current time is earlier than NotBefore condition #{(now + (options[:allowed_clock_drift] || 0))} < #{not_before})"
200212
return soft ? false : validation_error("Current time is earlier than NotBefore condition")
201213
end
202214

203215
if not_on_or_after && now >= not_on_or_after
216+
@errors << "Current time is on or after NotOnOrAfter condition (#{now} >= #{not_on_or_after})"
204217
return soft ? false : validation_error("Current time is on or after NotOnOrAfter condition")
205218
end
206219

lib/xml_security.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ class SignedDocument < REXML::Document
3838
DSIG = "http://www.w3.org/2000/09/xmldsig#"
3939

4040
attr_accessor :signed_element_id
41+
attr_accessor :errors
4142

42-
def initialize(response)
43+
def initialize(response, errors = [])
4344
super(response)
45+
@errors = errors
4446
extract_signed_element_id
4547
end
4648

@@ -62,6 +64,7 @@ def validate_document(idp_cert_fingerprint, soft = true)
6264
fingerprint = Digest::SHA1.hexdigest(cert.to_der)
6365

6466
if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
67+
@errors << "Fingerprint mismatch"
6568
return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Fingerprint mismatch"))
6669
end
6770

@@ -108,6 +111,7 @@ def validate_signature(base64_cert, soft = true)
108111
digest_value = Base64.decode64(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG}).text)
109112

110113
unless digests_match?(hash, digest_value)
114+
@errors << "Digest mismatch"
111115
return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Digest mismatch"))
112116
end
113117
end
@@ -123,6 +127,7 @@ def validate_signature(base64_cert, soft = true)
123127
signature_algorithm = algorithm(REXML::XPath.first(signed_info_element, "//ds:SignatureMethod", {"ds"=>DSIG}))
124128

125129
unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
130+
@errors << "Key validation error"
126131
return soft ? false : (raise OneLogin::RubySaml::ValidationError.new("Key validation error"))
127132
end
128133

test/response_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ class RubySamlTest < Test::Unit::TestCase
5353
end
5454
end
5555

56+
context "#validate_structure" do
57+
should "raise when encountering a condition that prevents the document from being valid" do
58+
response = OneLogin::RubySaml::Response.new(response_document_2)
59+
response.send(:validate_structure)
60+
assert response.errors.include? "Schema validation failed"
61+
end
62+
end
63+
5664
context "#is_valid?" do
5765
should "return false when response is initialized with blank data" do
5866
response = OneLogin::RubySaml::Response.new('')

test/xml_security_test.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ class XmlSecurityTest < Test::Unit::TestCase
4040
@document.validate_document("no:fi:ng:er:pr:in:t", false)
4141
end
4242
assert_equal("Fingerprint mismatch", exception.message)
43+
assert @document.errors.include? "Fingerprint mismatch"
4344
end
4445

4546
should "should raise Digest mismatch" do
4647
exception = assert_raise(OneLogin::RubySaml::ValidationError) do
4748
@document.validate_signature(@base64cert, false)
4849
end
4950
assert_equal("Digest mismatch", exception.message)
51+
assert @document.errors.include? "Digest mismatch"
5052
end
5153

5254
should "should raise Key validation error" do
@@ -59,6 +61,7 @@ class XmlSecurityTest < Test::Unit::TestCase
5961
document.validate_signature(base64cert, false)
6062
end
6163
assert_equal("Key validation error", exception.message)
64+
assert document.errors.include? "Key validation error"
6265
end
6366

6467
should "correctly obtain the digest method with alternate namespace declaration" do

0 commit comments

Comments
 (0)