ruby-saml 0.8.12

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.

Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +12 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +37 -0
  6. data/LICENSE +19 -0
  7. data/README.md +160 -0
  8. data/Rakefile +27 -0
  9. data/changelog.md +24 -0
  10. data/lib/onelogin/ruby-saml/attributes.rb +147 -0
  11. data/lib/onelogin/ruby-saml/authrequest.rb +168 -0
  12. data/lib/onelogin/ruby-saml/logging.rb +26 -0
  13. data/lib/onelogin/ruby-saml/logoutrequest.rb +161 -0
  14. data/lib/onelogin/ruby-saml/logoutresponse.rb +153 -0
  15. data/lib/onelogin/ruby-saml/metadata.rb +66 -0
  16. data/lib/onelogin/ruby-saml/response.rb +426 -0
  17. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  18. data/lib/onelogin/ruby-saml/settings.rb +166 -0
  19. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
  20. data/lib/onelogin/ruby-saml/utils.rb +119 -0
  21. data/lib/onelogin/ruby-saml/validation_error.rb +7 -0
  22. data/lib/onelogin/ruby-saml/version.rb +5 -0
  23. data/lib/ruby-saml.rb +12 -0
  24. data/lib/schemas/saml20assertion_schema.xsd +283 -0
  25. data/lib/schemas/saml20protocol_schema.xsd +302 -0
  26. data/lib/schemas/xenc_schema.xsd +146 -0
  27. data/lib/schemas/xmldsig_schema.xsd +318 -0
  28. data/lib/xml_security.rb +292 -0
  29. data/ruby-saml.gemspec +28 -0
  30. data/test/certificates/certificate1 +12 -0
  31. data/test/certificates/r1_certificate2_base64 +1 -0
  32. data/test/certificates/ruby-saml.crt +14 -0
  33. data/test/certificates/ruby-saml.key +15 -0
  34. data/test/logoutrequest_test.rb +244 -0
  35. data/test/logoutresponse_test.rb +112 -0
  36. data/test/request_test.rb +229 -0
  37. data/test/response_test.rb +475 -0
  38. data/test/responses/adfs_response_sha1.xml +46 -0
  39. data/test/responses/adfs_response_sha256.xml +46 -0
  40. data/test/responses/adfs_response_sha384.xml +46 -0
  41. data/test/responses/adfs_response_sha512.xml +46 -0
  42. data/test/responses/encrypted_new_attack.xml.base64 +1 -0
  43. data/test/responses/logoutresponse_fixtures.rb +67 -0
  44. data/test/responses/no_signature_ns.xml +48 -0
  45. data/test/responses/open_saml_response.xml +56 -0
  46. data/test/responses/r1_response6.xml.base64 +1 -0
  47. data/test/responses/response1.xml.base64 +1 -0
  48. data/test/responses/response2.xml.base64 +79 -0
  49. data/test/responses/response3.xml.base64 +66 -0
  50. data/test/responses/response4.xml.base64 +93 -0
  51. data/test/responses/response5.xml.base64 +102 -0
  52. data/test/responses/response_eval.xml +7 -0
  53. data/test/responses/response_node_text_attack.xml.base64 +1 -0
  54. data/test/responses/response_with_ampersands.xml +139 -0
  55. data/test/responses/response_with_ampersands.xml.base64 +93 -0
  56. data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
  57. data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
  58. data/test/responses/response_with_multiple_attribute_statements.xml +72 -0
  59. data/test/responses/response_with_multiple_attribute_values.xml +67 -0
  60. data/test/responses/response_wrapped.xml.base64 +150 -0
  61. data/test/responses/simple_saml_php.xml +71 -0
  62. data/test/responses/starfield_response.xml.base64 +1 -0
  63. data/test/responses/valid_response.xml.base64 +1 -0
  64. data/test/responses/wrapped_response_2.xml.base64 +150 -0
  65. data/test/settings_test.rb +47 -0
  66. data/test/slo_logoutresponse_test.rb +226 -0
  67. data/test/test_helper.rb +155 -0
  68. data/test/utils_test.rb +41 -0
  69. data/test/xml_security_test.rb +158 -0
  70. metadata +178 -0
@@ -0,0 +1,168 @@
1
+ require "base64"
2
+ require "zlib"
3
+ require "cgi"
4
+ require "onelogin/ruby-saml/utils"
5
+ require "onelogin/ruby-saml/setting_error"
6
+
7
+ module OneLogin
8
+ module RubySaml
9
+
10
+ class Authrequest
11
+ # AuthNRequest ID
12
+ attr_reader :uuid
13
+
14
+ # Initializes the AuthNRequest. An Authrequest Object.
15
+ # Asigns an ID, a random uuid.
16
+ #
17
+ def initialize
18
+ @uuid = OneLogin::RubySaml::Utils.uuid
19
+ end
20
+
21
+ def create(settings, params = {})
22
+ params = create_params(settings, params)
23
+ params_prefix = (settings.idp_sso_target_url =~ /\?/) ? '&' : '?'
24
+ saml_request = CGI.escape(params.delete("SAMLRequest"))
25
+ request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
26
+ params.each_pair do |key, value|
27
+ request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
28
+ end
29
+ raise SettingError.new "Invalid settings, idp_sso_target_url is not set!" if settings.idp_sso_target_url.nil? or settings.idp_sso_target_url.empty?
30
+ @login_url = settings.idp_sso_target_url + request_params
31
+ end
32
+
33
+ # Creates the Get parameters for the request.
34
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
35
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
36
+ # @return [Hash] Parameters
37
+ #
38
+ def create_params(settings, params={})
39
+ # The method expects :RelayState but sometimes we get 'RelayState' instead.
40
+ # Based on the HashWithIndifferentAccess value in Rails we could experience
41
+ # conflicts so this line will solve them.
42
+ relay_state = params[:RelayState] || params['RelayState']
43
+
44
+ if relay_state.nil?
45
+ params.delete(:RelayState)
46
+ params.delete('RelayState')
47
+ end
48
+
49
+ request_doc = create_authentication_xml_doc(settings)
50
+ request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
51
+
52
+ request = ""
53
+ request_doc.write(request)
54
+
55
+ Logging.debug "Created AuthnRequest: #{request}"
56
+
57
+ request = Zlib::Deflate.deflate(request, 9)[2..-5] if settings.compress_request
58
+ if Base64.respond_to?('strict_encode64')
59
+ base64_request = Base64.strict_encode64(request)
60
+ else
61
+ base64_request = Base64.encode64(request).gsub(/\n/, "")
62
+ end
63
+
64
+ request_params = {"SAMLRequest" => base64_request}
65
+
66
+ if settings.security[:authn_requests_signed] && !settings.security[:embed_sign] && settings.private_key
67
+ params['SigAlg'] = settings.security[:signature_method]
68
+ url_string = OneLogin::RubySaml::Utils.build_query(
69
+ :type => 'SAMLRequest',
70
+ :data => base64_request,
71
+ :relay_state => relay_state,
72
+ :sig_alg => params['SigAlg']
73
+ )
74
+ sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
75
+ signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
76
+ if Base64.respond_to?('strict_encode64')
77
+ params['Signature'] = Base64.strict_encode64(signature)
78
+ else
79
+ params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
80
+ end
81
+ end
82
+
83
+ params.each_pair do |key, value|
84
+ request_params[key] = value.to_s
85
+ end
86
+
87
+ request_params
88
+ end
89
+
90
+ def create_authentication_xml_doc(settings)
91
+ document = create_xml_document(settings)
92
+ sign_document(document, settings)
93
+ end
94
+
95
+ def create_xml_document(settings)
96
+ time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
97
+
98
+ request_doc = XMLSecurity::Document.new
99
+ request_doc.uuid = uuid
100
+
101
+ root = request_doc.add_element "samlp:AuthnRequest", { "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol", "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
102
+ root.attributes['ID'] = uuid
103
+ root.attributes['IssueInstant'] = time
104
+ root.attributes['Version'] = "2.0"
105
+ root.attributes['Destination'] = settings.idp_sso_target_url unless settings.idp_sso_target_url.nil? or settings.idp_sso_target_url.empty?
106
+ root.attributes['IsPassive'] = settings.passive unless settings.passive.nil?
107
+ root.attributes['ProtocolBinding'] = settings.protocol_binding unless settings.protocol_binding.nil?
108
+ root.attributes['ForceAuthn'] = settings.force_authn unless settings.force_authn.nil?
109
+
110
+ # Conditionally defined elements based on settings
111
+ if settings.assertion_consumer_service_url != nil
112
+ root.attributes["AssertionConsumerServiceURL"] = settings.assertion_consumer_service_url
113
+ end
114
+ if settings.sp_entity_id != nil
115
+ issuer = root.add_element "saml:Issuer"
116
+ issuer.text = settings.sp_entity_id
117
+ end
118
+
119
+ if settings.name_identifier_value_requested != nil
120
+ subject = root.add_element "saml:Subject"
121
+
122
+ nameid = subject.add_element "saml:NameID"
123
+ nameid.attributes['Format'] = settings.name_identifier_format if settings.name_identifier_format
124
+ nameid.text = settings.name_identifier_value_requested
125
+
126
+ subject_confirmation = subject.add_element "saml:SubjectConfirmation"
127
+ subject_confirmation.attributes['Method'] = "urn:oasis:names:tc:SAML:2.0:cm:bearer"
128
+ end
129
+
130
+ if settings.name_identifier_format != nil
131
+ root.add_element "samlp:NameIDPolicy", {
132
+ "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
133
+ # Might want to make AllowCreate a setting?
134
+ "AllowCreate" => "true",
135
+ "Format" => settings.name_identifier_format
136
+ }
137
+ end
138
+
139
+ # BUG fix here -- if an authn_context is defined, add the tags with an "exact"
140
+ # match required for authentication to succeed. If this is not defined,
141
+ # the IdP will choose default rules for authentication. (Shibboleth IdP)
142
+ if settings.authn_context != nil
143
+ requested_context = root.add_element "samlp:RequestedAuthnContext", {
144
+ "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
145
+ "Comparison" => "exact",
146
+ }
147
+ class_ref = requested_context.add_element "saml:AuthnContextClassRef", {
148
+ "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion",
149
+ }
150
+ class_ref.text = settings.authn_context
151
+ end
152
+ request_doc
153
+ end
154
+
155
+ def sign_document(document, settings)
156
+ # embed signature
157
+ if settings.security[:authn_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
158
+ private_key = settings.get_sp_key
159
+ cert = settings.get_sp_cert
160
+ document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
161
+ end
162
+
163
+ document
164
+ end
165
+
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,26 @@
1
+ # Simplistic log class when we're running in Rails
2
+ module OneLogin
3
+ module RubySaml
4
+ class Logging
5
+ def self.debug(message)
6
+ return if !!ENV["ruby-saml/testing"]
7
+
8
+ if defined? Rails
9
+ Rails.logger.debug message
10
+ else
11
+ puts message
12
+ end
13
+ end
14
+
15
+ def self.info(message)
16
+ return if !!ENV["ruby-saml/testing"]
17
+
18
+ if defined? Rails
19
+ Rails.logger.info message
20
+ else
21
+ puts message
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,161 @@
1
+ require "base64"
2
+ require "zlib"
3
+ require "cgi"
4
+ require 'rexml/document'
5
+ require "onelogin/ruby-saml/utils"
6
+ require "onelogin/ruby-saml/setting_error"
7
+
8
+ module OneLogin
9
+ module RubySaml
10
+
11
+ class Logoutrequest
12
+
13
+ attr_reader :uuid # Can be obtained if neccessary
14
+
15
+ def initialize
16
+ @uuid = OneLogin::RubySaml::Utils.uuid
17
+ end
18
+
19
+ def create(settings, params={})
20
+ params = create_params(settings, params)
21
+ params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
22
+ saml_request = CGI.escape(params.delete("SAMLRequest"))
23
+ request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
24
+ params.each_pair do |key, value|
25
+ request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
26
+ end
27
+ raise SettingError.new "Invalid settings, idp_slo_target_url is not set!" if settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
28
+ @logout_url = settings.idp_slo_target_url + request_params
29
+ end
30
+
31
+ # Creates the Get parameters for the logout request.
32
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
33
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
34
+ # @return [Hash] Parameters
35
+ #
36
+ def create_params(settings, params={})
37
+ # The method expects :RelayState but sometimes we get 'RelayState' instead.
38
+ # Based on the HashWithIndifferentAccess value in Rails we could experience
39
+ # conflicts so this line will solve them.
40
+ relay_state = params[:RelayState] || params['RelayState']
41
+
42
+ if relay_state.nil?
43
+ params.delete(:RelayState)
44
+ params.delete('RelayState')
45
+ end
46
+
47
+ request_doc = create_logout_request_xml_doc(settings)
48
+ request_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
49
+
50
+ request = ""
51
+ request_doc.write(request)
52
+
53
+ Logging.debug "Created SLO Logout Request: #{request}"
54
+
55
+ request = Zlib::Deflate.deflate(request, 9)[2..-5] if settings.compress_request
56
+ if Base64.respond_to?('strict_encode64')
57
+ base64_request = Base64.strict_encode64(request)
58
+ else
59
+ base64_request = Base64.encode64(request).gsub(/\n/, "")
60
+ end
61
+ request_params = {"SAMLRequest" => base64_request}
62
+
63
+ if settings.security[:logout_requests_signed] && !settings.security[:embed_sign] && settings.private_key
64
+ params['SigAlg'] = settings.security[:signature_method]
65
+ url_string = OneLogin::RubySaml::Utils.build_query(
66
+ :type => 'SAMLRequest',
67
+ :data => base64_request,
68
+ :relay_state => relay_state,
69
+ :sig_alg => params['SigAlg']
70
+ )
71
+ sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
72
+ signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
73
+ if Base64.respond_to?('strict_encode64')
74
+ params['Signature'] = Base64.strict_encode64(signature)
75
+ else
76
+ params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
77
+ end
78
+ end
79
+
80
+ params.each_pair do |key, value|
81
+ request_params[key] = value.to_s
82
+ end
83
+
84
+ request_params
85
+ end
86
+
87
+ # Creates the SAMLRequest String.
88
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
89
+ # @return [String] The SAMLRequest String.
90
+ #
91
+ def create_logout_request_xml_doc(settings)
92
+ document = create_xml_document(settings)
93
+ sign_document(document, settings)
94
+ end
95
+
96
+ def create_xml_document(settings, request_doc=nil)
97
+ time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
98
+
99
+ if request_doc.nil?
100
+ request_doc = XMLSecurity::Document.new
101
+ request_doc.uuid = uuid
102
+ end
103
+
104
+ root = request_doc.add_element "samlp:LogoutRequest", { "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol" }
105
+ root.attributes['ID'] = uuid
106
+ root.attributes['IssueInstant'] = time
107
+ root.attributes['Version'] = "2.0"
108
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil? or settings.idp_slo_target_url.empty?
109
+
110
+ if settings.sp_entity_id
111
+ issuer = root.add_element "saml:Issuer", { "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
112
+ issuer.text = settings.sp_entity_id
113
+ end
114
+
115
+ if settings.name_identifier_value
116
+ name_id = root.add_element "saml:NameID", { "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
117
+ name_id.attributes['NameQualifier'] = settings.sp_name_qualifier if settings.sp_name_qualifier
118
+ name_id.attributes['Format'] = settings.name_identifier_format if settings.name_identifier_format
119
+ name_id.text = settings.name_identifier_value
120
+ end
121
+
122
+ if settings.sessionindex
123
+ sessionindex = root.add_element "samlp:SessionIndex", { "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol" }
124
+ sessionindex.text = settings.sessionindex
125
+ end
126
+
127
+ # BUG fix here -- if an authn_context is defined, add the tags with an "exact"
128
+ # match required for authentication to succeed. If this is not defined,
129
+ # the IdP will choose default rules for authentication. (Shibboleth IdP)
130
+ if settings.authn_context != nil
131
+ requested_context = root.add_element "samlp:RequestedAuthnContext", {
132
+ "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
133
+ "Comparison" => "exact",
134
+ }
135
+ class_ref = requested_context.add_element "saml:AuthnContextClassRef", {
136
+ "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion",
137
+ }
138
+ class_ref.text = settings.authn_context
139
+ end
140
+ request_doc
141
+ end
142
+
143
+ def sign_document(document, settings)
144
+ # embed signature
145
+ if settings.security[:logout_requests_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
146
+ private_key = settings.get_sp_key
147
+ cert = settings.get_sp_cert
148
+ document.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
149
+ end
150
+
151
+ document
152
+ end
153
+
154
+ # Leave due compatibility
155
+ def create_unauth_xml_doc(settings, params)
156
+ request_doc = ReXML::Document.new
157
+ create_xml_document(settings, request_doc)
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,153 @@
1
+ require "xml_security"
2
+ require "time"
3
+ require "base64"
4
+ require "zlib"
5
+
6
+ module OneLogin
7
+ module RubySaml
8
+ class Logoutresponse
9
+
10
+ ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
11
+ PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
12
+
13
+ # For API compability, this is mutable.
14
+ attr_accessor :settings
15
+
16
+ attr_reader :document
17
+ attr_reader :response
18
+ attr_reader :options
19
+
20
+ #
21
+ # In order to validate that the response matches a given request, append
22
+ # the option:
23
+ # :matches_request_id => REQUEST_ID
24
+ #
25
+ # It will validate that the logout response matches the ID of the request.
26
+ # You can also do this yourself through the in_response_to accessor.
27
+ #
28
+ def initialize(response, settings = nil, options = {})
29
+ raise ArgumentError.new("Logoutresponse cannot be nil") if response.nil?
30
+ self.settings = settings
31
+
32
+ @options = options
33
+ @response = decode_raw_response(response)
34
+ @document = XMLSecurity::SignedDocument.new(response)
35
+ end
36
+
37
+ def validate!
38
+ validate(false)
39
+ end
40
+
41
+ def validate(soft = true)
42
+ return false unless valid_saml?(soft) && valid_state?(soft)
43
+
44
+ valid_in_response_to?(soft) && valid_issuer?(soft) && success?(soft)
45
+ end
46
+
47
+ def success?(soft = true)
48
+ unless status_code == "urn:oasis:names:tc:SAML:2.0:status:Success"
49
+ return soft ? false : validation_error("Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <#@status_code> ")
50
+ end
51
+ true
52
+ end
53
+
54
+ def in_response_to
55
+ @in_response_to ||= begin
56
+ node = REXML::XPath.first(document, "/p:LogoutResponse", { "p" => PROTOCOL, "a" => ASSERTION })
57
+ node.nil? ? nil : node.attributes['InResponseTo']
58
+ end
59
+ end
60
+
61
+ def issuer
62
+ @issuer ||= begin
63
+ node = REXML::XPath.first(document, "/p:LogoutResponse/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
64
+ node ||= REXML::XPath.first(document, "/p:LogoutResponse/a:Assertion/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
65
+ Utils.element_text(node)
66
+ end
67
+ end
68
+
69
+ def status_code
70
+ @status_code ||= begin
71
+ node = REXML::XPath.first(document, "/p:LogoutResponse/p:Status/p:StatusCode", { "p" => PROTOCOL, "a" => ASSERTION })
72
+ node.nil? ? nil : node.attributes["Value"]
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def decode(encoded)
79
+ Base64.decode64(encoded)
80
+ end
81
+
82
+ def inflate(deflated)
83
+ zlib = Zlib::Inflate.new(-Zlib::MAX_WBITS)
84
+ zlib.inflate(deflated)
85
+ end
86
+
87
+ def decode_raw_response(response)
88
+ if response =~ /^</
89
+ return response
90
+ elsif (decoded = decode(response)) =~ /^</
91
+ return decoded
92
+ elsif (inflated = inflate(decoded)) =~ /^</
93
+ return inflated
94
+ end
95
+
96
+ raise "Couldn't decode SAMLResponse"
97
+ end
98
+
99
+ def valid_saml?(soft = true)
100
+ Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
101
+ @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
102
+ @xml = Nokogiri::XML(self.document.to_s)
103
+ end
104
+ if soft
105
+ @schema.validate(@xml).map{ return false }
106
+ else
107
+ @schema.validate(@xml).map{ |error| validation_error("#{error.message}\n\n#{@xml.to_s}") }
108
+ end
109
+ end
110
+
111
+ def valid_state?(soft = true)
112
+ if response.empty?
113
+ return soft ? false : validation_error("Blank response")
114
+ end
115
+
116
+ if settings.nil?
117
+ return soft ? false : validation_error("No settings on response")
118
+ end
119
+
120
+ if settings.sp_entity_id.nil?
121
+ return soft ? false : validation_error("No sp_entity_id in settings")
122
+ end
123
+
124
+ if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil?
125
+ return soft ? false : validation_error("No fingerprint or certificate on settings")
126
+ end
127
+
128
+ true
129
+ end
130
+
131
+ def valid_in_response_to?(soft = true)
132
+ return true unless self.options.has_key? :matches_request_id
133
+
134
+ unless self.options[:matches_request_id] == in_response_to
135
+ return soft ? false : validation_error("Response does not match the request ID, expected: <#{self.options[:matches_request_id]}>, but was: <#{in_response_to}>")
136
+ end
137
+
138
+ true
139
+ end
140
+
141
+ def valid_issuer?(soft = true)
142
+ unless URI.parse(issuer) == URI.parse(self.settings.sp_entity_id)
143
+ return soft ? false : validation_error("Doesn't match the issuer, expected: <#{self.settings.sp_entity_id}>, but was: <#{issuer}>")
144
+ end
145
+ true
146
+ end
147
+
148
+ def validation_error(message)
149
+ raise ValidationError.new(message)
150
+ end
151
+ end
152
+ end
153
+ end