saml2 3.1.2 → 3.1.4

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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +6 -4
  3. data/exe/bulk_verify_responses +94 -0
  4. data/lib/saml2/assertion.rb +7 -7
  5. data/lib/saml2/attribute/x500.rb +31 -28
  6. data/lib/saml2/attribute.rb +53 -49
  7. data/lib/saml2/attribute_consuming_service.rb +29 -31
  8. data/lib/saml2/authn_request.rb +54 -47
  9. data/lib/saml2/authn_statement.rb +31 -20
  10. data/lib/saml2/base.rb +72 -63
  11. data/lib/saml2/bindings/http_post.rb +7 -7
  12. data/lib/saml2/bindings/http_redirect.rb +37 -33
  13. data/lib/saml2/bindings.rb +1 -1
  14. data/lib/saml2/conditions.rb +19 -16
  15. data/lib/saml2/contact.rb +19 -18
  16. data/lib/saml2/endpoint.rb +14 -11
  17. data/lib/saml2/entity.rb +27 -27
  18. data/lib/saml2/identity_provider.rb +13 -10
  19. data/lib/saml2/indexed_object.rb +15 -12
  20. data/lib/saml2/key.rb +43 -34
  21. data/lib/saml2/localized_name.rb +11 -10
  22. data/lib/saml2/logout_request.rb +8 -8
  23. data/lib/saml2/logout_response.rb +4 -4
  24. data/lib/saml2/message.rb +24 -20
  25. data/lib/saml2/name_id.rb +45 -41
  26. data/lib/saml2/namespaces.rb +8 -8
  27. data/lib/saml2/organization.rb +11 -10
  28. data/lib/saml2/organization_and_contacts.rb +5 -5
  29. data/lib/saml2/request.rb +3 -3
  30. data/lib/saml2/requested_authn_context.rb +4 -4
  31. data/lib/saml2/response.rb +45 -33
  32. data/lib/saml2/role.rb +11 -11
  33. data/lib/saml2/schemas.rb +13 -10
  34. data/lib/saml2/service_provider.rb +11 -12
  35. data/lib/saml2/signable.rb +23 -18
  36. data/lib/saml2/sso.rb +5 -5
  37. data/lib/saml2/status.rb +9 -7
  38. data/lib/saml2/status_response.rb +5 -5
  39. data/lib/saml2/subject.rb +28 -28
  40. data/lib/saml2/version.rb +1 -1
  41. data/lib/saml2.rb +7 -7
  42. metadata +78 -122
  43. data/spec/fixtures/FederationMetadata.xml +0 -670
  44. data/spec/fixtures/authnrequest.xml +0 -12
  45. data/spec/fixtures/certificate.pem +0 -24
  46. data/spec/fixtures/entities.xml +0 -13
  47. data/spec/fixtures/external-uri-reference-response.xml +0 -48
  48. data/spec/fixtures/identity_provider.xml +0 -46
  49. data/spec/fixtures/noconditions_response.xml +0 -1
  50. data/spec/fixtures/othercertificate.pem +0 -25
  51. data/spec/fixtures/privatekey.key +0 -27
  52. data/spec/fixtures/response_assertion_signed_reffed_from_response.xml +0 -6
  53. data/spec/fixtures/response_signed.xml +0 -46
  54. data/spec/fixtures/response_tampered_certificate.xml +0 -25
  55. data/spec/fixtures/response_tampered_signature.xml +0 -46
  56. data/spec/fixtures/response_with_attribute_signed.xml +0 -46
  57. data/spec/fixtures/response_with_encrypted_assertion.xml +0 -58
  58. data/spec/fixtures/response_with_rsa_key_value.xml +0 -1
  59. data/spec/fixtures/response_with_signed_assertion_and_encrypted_subject.xml +0 -116
  60. data/spec/fixtures/response_without_keyinfo.xml +0 -1
  61. data/spec/fixtures/service_provider.xml +0 -79
  62. data/spec/fixtures/test3-response.xml +0 -9
  63. data/spec/fixtures/test6-response.xml +0 -10
  64. data/spec/fixtures/test7-response.xml +0 -10
  65. data/spec/fixtures/xml_missigned_assertion.xml +0 -84
  66. data/spec/fixtures/xml_signature_wrapping_attack_duplicate_ids.xml +0 -11
  67. data/spec/fixtures/xml_signature_wrapping_attack_response_attributes.xml +0 -45
  68. data/spec/fixtures/xml_signature_wrapping_attack_response_nameid.xml +0 -44
  69. data/spec/fixtures/xslt-transform-response.xml +0 -57
  70. data/spec/lib/attribute_consuming_service_spec.rb +0 -129
  71. data/spec/lib/attribute_spec.rb +0 -149
  72. data/spec/lib/authn_request_spec.rb +0 -52
  73. data/spec/lib/bindings/http_redirect_spec.rb +0 -183
  74. data/spec/lib/conditions_spec.rb +0 -74
  75. data/spec/lib/entity_spec.rb +0 -58
  76. data/spec/lib/identity_provider_spec.rb +0 -43
  77. data/spec/lib/indexed_object_spec.rb +0 -71
  78. data/spec/lib/key_spec.rb +0 -23
  79. data/spec/lib/logout_request_spec.rb +0 -33
  80. data/spec/lib/logout_response_spec.rb +0 -33
  81. data/spec/lib/message_spec.rb +0 -23
  82. data/spec/lib/response_spec.rb +0 -293
  83. data/spec/lib/service_provider_spec.rb +0 -76
  84. data/spec/lib/signable_spec.rb +0 -15
  85. data/spec/spec_helper.rb +0 -8
@@ -1,17 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'nokogiri-xmlsec'
4
- require 'time'
3
+ require "nokogiri-xmlsec"
4
+ require "time"
5
5
 
6
- require 'saml2/assertion'
7
- require 'saml2/authn_statement'
8
- require 'saml2/status_response'
9
- require 'saml2/subject'
6
+ require "saml2/assertion"
7
+ require "saml2/authn_statement"
8
+ require "saml2/status_response"
9
+ require "saml2/subject"
10
10
 
11
11
  module SAML2
12
12
  class Response < StatusResponse
13
- attr_reader :assertions
14
-
15
13
  # Respond to an {AuthnRequest}
16
14
  #
17
15
  # {AuthnRequest#resolve} needs to have been previously called on the {AuthnRequest}.
@@ -98,7 +96,11 @@ module SAML2
98
96
  verification_time: nil,
99
97
  ignore_audience_condition: false)
100
98
  raise ArgumentError, "service_provider should be an Entity object" unless service_provider.is_a?(Entity)
101
- raise ArgumentError, "service_provider should have at least one service_provider role" unless (sp = service_provider.service_providers.first)
99
+
100
+ unless (sp = service_provider.service_providers.first)
101
+ raise ArgumentError,
102
+ "service_provider should have at least one service_provider role"
103
+ end
102
104
 
103
105
  # validate the schema
104
106
  super()
@@ -108,7 +110,9 @@ module SAML2
108
110
  verification_time = Time.now.utc
109
111
  # they issued it in the (near) future according to our clock;
110
112
  # use their clock instead
111
- verification_time = issue_instant if issue_instant > verification_time && issue_instant < verification_time + 5 * 60
113
+ if issue_instant > verification_time && issue_instant < verification_time + (5 * 60)
114
+ verification_time = issue_instant
115
+ end
112
116
  end
113
117
 
114
118
  # not finding the issuer is not exceptional
@@ -119,16 +123,21 @@ module SAML2
119
123
 
120
124
  # getting the wrong data type is exceptional, and we should raise an error
121
125
  raise ArgumentError, "identity_provider should be an Entity object" unless identity_provider.is_a?(Entity)
122
- raise ArgumentError, "identity_provider should have at least one identity_provider role" unless (idp = identity_provider.identity_providers.first)
126
+
127
+ unless (idp = identity_provider.identity_providers.first)
128
+ raise ArgumentError,
129
+ "identity_provider should have at least one identity_provider role"
130
+ end
123
131
 
124
132
  issuer = self.issuer || assertions.first&.issuer
125
133
  unless identity_provider.entity_id == issuer&.id
126
- errors << "received unexpected message from '#{issuer&.id}'; expected it to be from '#{identity_provider.entity_id}'"
134
+ errors << "received unexpected message from '#{issuer&.id}'; " \
135
+ "expected it to be from '#{identity_provider.entity_id}'"
127
136
  return errors
128
137
  end
129
138
 
130
- certificates = idp.signing_keys.map(&:certificate).compact
131
- keys = idp.signing_keys.map(&:key).compact
139
+ certificates = idp.signing_keys.filter_map(&:certificate)
140
+ keys = idp.signing_keys.filter_map(&:key)
132
141
  if idp.fingerprints.empty? && certificates.empty? && keys.empty?
133
142
  errors << "could not find certificate to validate message"
134
143
  return errors
@@ -140,6 +149,7 @@ module SAML2
140
149
  cert: certificates)).empty?
141
150
  return errors.concat(signature_errors)
142
151
  end
152
+
143
153
  response_signed = true
144
154
  end
145
155
 
@@ -152,24 +162,27 @@ module SAML2
152
162
  cert: certificates)).empty?
153
163
  return errors.concat(signature_errors)
154
164
  end
165
+
155
166
  assertion_signed = true
156
167
  end
157
168
 
158
- find_decryption_key = ->(embedded_certificates) do
169
+ find_decryption_key = lambda do |embedded_certificates|
159
170
  key = nil
160
171
  embedded_certificates.each do |cert_info|
161
172
  cert = case cert_info
162
- when OpenSSL::X509::Certificate; cert_info
163
- when Hash; sp.encryption_keys.map(&:certificate).find { |c| c.serial == cert_info[:serial] }
173
+ when OpenSSL::X509::Certificate then cert_info
174
+ when Hash then sp.encryption_keys.map(&:certificate).find { |c| c.serial == cert_info[:serial] }
164
175
  end
165
176
  next unless cert
177
+
166
178
  key = sp.private_keys.find { |k| cert.check_private_key(k) }
167
179
  break if key
168
180
  end
169
- if !key
181
+ unless key
170
182
  # couldn't figure out which key to use; just try them all
171
183
  next sp.private_keys
172
184
  end
185
+
173
186
  key
174
187
  end
175
188
 
@@ -208,23 +221,24 @@ module SAML2
208
221
  cert: certificates)).empty?
209
222
  return errors.concat(signature_errors)
210
223
  end
224
+
211
225
  assertion_signed = true
212
226
  end
213
227
 
214
228
  # only do our own issue instant validation if the assertion
215
229
  # doesn't mandate any
216
- unless assertion.conditions&.not_on_or_after
217
- if assertion.issue_instant + 5 * 60 < verification_time ||
218
- assertion.issue_instant - 5 * 60 > verification_time
219
- errors << "assertion not recently issued"
220
- return errors
221
- end
230
+ if !assertion.conditions&.not_on_or_after && (assertion.issue_instant + (5 * 60) < verification_time ||
231
+ assertion.issue_instant - (5 * 60) > verification_time)
232
+ errors << "assertion not recently issued"
233
+ return errors
222
234
  end
223
235
 
224
236
  if assertion.conditions &&
225
- !(condition_errors = assertion.conditions.validate(verification_time: verification_time,
226
- audience: service_provider.entity_id,
227
- ignore_audience_condition: ignore_audience_condition)).empty?
237
+ !(condition_errors = assertion.conditions.validate(
238
+ verification_time: verification_time,
239
+ audience: service_provider.entity_id,
240
+ ignore_audience_condition: ignore_audience_condition
241
+ )).empty?
228
242
  return errors.concat(condition_errors)
229
243
  end
230
244
 
@@ -253,9 +267,7 @@ module SAML2
253
267
 
254
268
  # @return [Array<Assertion>]
255
269
  def assertions
256
- unless instance_variable_defined?(:@assertions)
257
- @assertions = load_object_array(xml, 'saml:Assertion', Assertion)
258
- end
270
+ @assertions = load_object_array(xml, "saml:Assertion", Assertion) unless instance_variable_defined?(:@assertions)
259
271
  @assertions
260
272
  end
261
273
 
@@ -275,9 +287,9 @@ module SAML2
275
287
  private
276
288
 
277
289
  def build(builder)
278
- builder['samlp'].Response(
279
- 'xmlns:samlp' => Namespaces::SAMLP,
280
- 'xmlns:saml' => Namespaces::SAML
290
+ builder["samlp"].Response(
291
+ "xmlns:samlp" => Namespaces::SAMLP,
292
+ "xmlns:saml" => Namespaces::SAML
281
293
  ) do |response|
282
294
  super(response)
283
295
 
data/lib/saml2/role.rb CHANGED
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
3
+ require "set"
4
4
 
5
- require 'saml2/base'
6
- require 'saml2/key'
7
- require 'saml2/organization_and_contacts'
8
- require 'saml2/signable'
5
+ require "saml2/base"
6
+ require "saml2/key"
7
+ require "saml2/organization_and_contacts"
8
+ require "saml2/signable"
9
9
 
10
10
  module SAML2
11
11
  # @abstract
12
12
  class Role < Base
13
13
  module Protocols
14
- SAML2 = 'urn:oasis:names:tc:SAML:2.0:protocol'
14
+ SAML2 = "urn:oasis:names:tc:SAML:2.0:protocol"
15
15
  end
16
16
 
17
17
  include OrganizationAndContacts
@@ -47,29 +47,29 @@ module SAML2
47
47
  # @see Protocols
48
48
  # @return [Array<String>]
49
49
  def supported_protocols
50
- @supported_protocols ||= xml['protocolSupportEnumeration'].split
50
+ @supported_protocols ||= xml["protocolSupportEnumeration"].split
51
51
  end
52
52
 
53
53
  # @return [Array<KeyDescriptor>]
54
54
  def keys
55
- @keys ||= load_object_array(xml, 'md:KeyDescriptor', KeyDescriptor)
55
+ @keys ||= load_object_array(xml, "md:KeyDescriptor", KeyDescriptor)
56
56
  end
57
57
 
58
58
  # @return [Array<KeyDescriptor>]
59
59
  def signing_keys
60
- keys.select { |key| key.signing? }
60
+ keys.select(&:signing?)
61
61
  end
62
62
 
63
63
  # @return [Array<KeyDescriptor>]
64
64
  def encryption_keys
65
- keys.select { |key| key.encryption? }
65
+ keys.select(&:encryption?)
66
66
  end
67
67
 
68
68
  protected
69
69
 
70
70
  # should be called from inside the role element
71
71
  def build(builder)
72
- builder.parent['protocolSupportEnumeration'] = supported_protocols.to_a.join(' ')
72
+ builder.parent["protocolSupportEnumeration"] = supported_protocols.to_a.join(" ")
73
73
  keys.each do |key|
74
74
  key.build(builder)
75
75
  end
data/lib/saml2/schemas.rb CHANGED
@@ -2,18 +2,21 @@
2
2
 
3
3
  module SAML2
4
4
  module Schemas
5
- def self.metadata
6
- @metadata ||= schema('metadata_combined.xsd')
7
- end
5
+ class << self
6
+ def metadata
7
+ @metadata ||= schema("metadata_combined.xsd")
8
+ end
8
9
 
9
- def self.protocol
10
- @protocol ||= schema('saml-schema-protocol-2.0.xsd')
11
- end
10
+ def protocol
11
+ @protocol ||= schema("saml-schema-protocol-2.0.xsd")
12
+ end
13
+
14
+ private
12
15
 
13
- private
14
- def self.schema(filename)
15
- Dir.chdir(File.expand_path(File.join(__FILE__, '../../../schemas'))) do
16
- Nokogiri::XML::Schema(File.read(filename))
16
+ def schema(filename)
17
+ Dir.chdir(File.expand_path(File.join(__FILE__, "../../../schemas"))) do
18
+ Nokogiri::XML::Schema(File.read(filename))
19
+ end
17
20
  end
18
21
  end
19
22
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'nokogiri'
3
+ require "nokogiri"
4
4
 
5
- require 'saml2/endpoint'
6
- require 'saml2/sso'
5
+ require "saml2/endpoint"
6
+ require "saml2/sso"
7
7
 
8
8
  module SAML2
9
9
  class ServiceProvider < SSO
@@ -29,7 +29,7 @@ module SAML2
29
29
  # @return [Boolean, nil]
30
30
  def authn_requests_signed?
31
31
  unless instance_variable_defined?(:@authn_requests_signed)
32
- @authn_requests_signed = xml['AuthnRequestsSigned'] && xml['AuthnRequestsSigned'] == 'true'
32
+ @authn_requests_signed = xml["AuthnRequestsSigned"] && xml["AuthnRequestsSigned"] == "true"
33
33
  end
34
34
  @authn_requests_signed
35
35
  end
@@ -37,7 +37,7 @@ module SAML2
37
37
  # @return [Boolean, nil]
38
38
  def want_assertions_signed?
39
39
  unless instance_variable_defined?(:@want_assertions_signed)
40
- @want_assertions_signed = xml['WantAssertionsSigned'] && xml['WantAssertionsSigned'] == 'true'
40
+ @want_assertions_signed = xml["WantAssertionsSigned"] && xml["WantAssertionsSigned"] == "true"
41
41
  end
42
42
  @want_assertions_signed
43
43
  end
@@ -45,7 +45,7 @@ module SAML2
45
45
  # @return [Endpoint::Indexed::Array]
46
46
  def assertion_consumer_services
47
47
  @assertion_consumer_services ||= begin
48
- nodes = xml.xpath('md:AssertionConsumerService', Namespaces::ALL)
48
+ nodes = xml.xpath("md:AssertionConsumerService", Namespaces::ALL)
49
49
  Endpoint::Indexed::Array.from_xml(nodes)
50
50
  end
51
51
  end
@@ -53,21 +53,21 @@ module SAML2
53
53
  # @return [AttributeConsumingService::Array]
54
54
  def attribute_consuming_services
55
55
  @attribute_consuming_services ||= begin
56
- nodes = xml.xpath('md:AttributeConsumingService', Namespaces::ALL)
56
+ nodes = xml.xpath("md:AttributeConsumingService", Namespaces::ALL)
57
57
  AttributeConsumingService::Array.from_xml(nodes)
58
58
  end
59
59
  end
60
60
 
61
61
  # (see Base#build)
62
62
  def build(builder)
63
- builder['md'].SPSSODescriptor do |sp_sso_descriptor|
63
+ builder["md"].SPSSODescriptor do |sp_sso_descriptor|
64
64
  super(sp_sso_descriptor)
65
65
 
66
- sp_sso_descriptor.parent['AuthnRequestsSigned'] = authn_requests_signed? unless authn_requests_signed?.nil?
67
- sp_sso_descriptor.parent['WantAssertionsSigned'] = want_assertions_signed? unless authn_requests_signed?.nil?
66
+ sp_sso_descriptor.parent["AuthnRequestsSigned"] = authn_requests_signed? unless authn_requests_signed?.nil?
67
+ sp_sso_descriptor.parent["WantAssertionsSigned"] = want_assertions_signed? unless authn_requests_signed?.nil?
68
68
 
69
69
  assertion_consumer_services.each do |acs|
70
- acs.build(sp_sso_descriptor, 'AssertionConsumerService')
70
+ acs.build(sp_sso_descriptor, "AssertionConsumerService")
71
71
  end
72
72
 
73
73
  attribute_consuming_services.each do |acs|
@@ -77,4 +77,3 @@ module SAML2
77
77
  end
78
78
  end
79
79
  end
80
-
@@ -1,21 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/key'
3
+ require "saml2/key"
4
4
 
5
5
  module SAML2
6
6
  module Signable
7
7
  # @return [Nokogiri::XML::Element, nil]
8
8
  def signature
9
9
  unless instance_variable_defined?(:@signature)
10
- @signature = xml.xpath('//dsig:Signature', Namespaces::ALL).find do |signature|
11
- signed_node = signature.at_xpath('dsig:SignedInfo/dsig:Reference', Namespaces::ALL)['URI']
12
- if signed_node == ''
10
+ @signature = xml.xpath("//dsig:Signature", Namespaces::ALL).find do |signature|
11
+ signed_node = signature.at_xpath("dsig:SignedInfo/dsig:Reference", Namespaces::ALL)["URI"]
12
+ if signed_node == ""
13
13
  true if xml == xml.document.root
14
- elsif signed_node != "##{xml['ID']}"
14
+ elsif signed_node != "##{xml["ID"]}"
15
15
  false
16
16
  else
17
17
  # validating the schema will automatically add ID attributes, so check that first
18
- xml.set_id_attribute('ID') unless xml.document.get_id(xml['ID'])
18
+ xml.set_id_attribute("ID") unless xml.document.get_id(xml["ID"])
19
19
  true
20
20
  end
21
21
  end
@@ -27,7 +27,12 @@ module SAML2
27
27
  def signing_key
28
28
  unless instance_variable_defined?(:@signing_key)
29
29
  # don't use `... if signature.at_xpath(...)` - we need to make sure we assign the nil
30
- @signing_key = (key_info = signature.at_xpath('dsig:KeyInfo', Namespaces::ALL)) ? KeyInfo.from_xml(key_info) : nil
30
+ @signing_key = if (key_info = signature.at_xpath("dsig:KeyInfo",
31
+ Namespaces::ALL))
32
+ KeyInfo.from_xml(key_info)
33
+ else
34
+ nil
35
+ end
31
36
  end
32
37
  @signing_key
33
38
  end
@@ -69,19 +74,15 @@ module SAML2
69
74
  certs = certs.uniq
70
75
 
71
76
  trusted_keys = Array.wrap(key).map(&:to_s)
72
- trusted_keys.concat(certs.map do |cert|
73
- cert = cert.is_a?(String) ? OpenSSL::X509::Certificate.new(cert) : cert
74
- cert.public_key.to_s
77
+ trusted_keys.concat(certs.map do |certificate|
78
+ certificate = OpenSSL::X509::Certificate.new(certificate) if certificate.is_a?(String)
79
+ certificate.public_key.to_s
75
80
  end)
76
81
 
77
- if trusted_keys.include?(signing_key&.public_key&.to_s)
78
- verification_key = signing_key.public_key.to_s
79
- end
82
+ verification_key = signing_key.public_key.to_s if trusted_keys.include?(signing_key&.public_key&.to_s)
80
83
  # signature doesn't say who signed it. hope and pray it's with the only certificate
81
84
  # we know about
82
- if signing_key.nil?
83
- verification_key = trusted_keys.first
84
- end
85
+ verification_key = trusted_keys.first if signing_key.nil?
85
86
 
86
87
  return ["no trusted signing key found"] if verification_key.nil?
87
88
 
@@ -116,8 +117,12 @@ module SAML2
116
117
  to_xml
117
118
 
118
119
  xml = @document.root
119
- xml.set_id_attribute('ID')
120
- xml.sign!(cert: x509_certificate, key: private_key, digest_alg: algorithm_name.to_s, signature_alg: "rsa-#{algorithm_name}", uri: "##{id}")
120
+ xml.set_id_attribute("ID")
121
+ xml.sign!(cert: x509_certificate,
122
+ key: private_key,
123
+ digest_alg: algorithm_name.to_s,
124
+ signature_alg: "rsa-#{algorithm_name}",
125
+ uri: "##{id}")
121
126
  # the Signature element must be the first element
122
127
  signature = xml.at_xpath("dsig:Signature", Namespaces::ALL)
123
128
  xml.children.first.add_previous_sibling(signature)
data/lib/saml2/sso.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/role'
3
+ require "saml2/role"
4
4
 
5
5
  module SAML2
6
6
  # @abstract
@@ -20,12 +20,12 @@ module SAML2
20
20
 
21
21
  # @return [Array<Endpoint>]
22
22
  def single_logout_services
23
- @single_logout_services ||= load_object_array(xml, 'md:SingleLogoutService', Endpoint)
23
+ @single_logout_services ||= load_object_array(xml, "md:SingleLogoutService", Endpoint)
24
24
  end
25
25
 
26
26
  # @return [Array<String>]
27
27
  def name_id_formats
28
- @name_id_formats ||= load_string_array(xml, 'md:NameIDFormat')
28
+ @name_id_formats ||= load_string_array(xml, "md:NameIDFormat")
29
29
  end
30
30
 
31
31
  protected
@@ -35,10 +35,10 @@ module SAML2
35
35
  super
36
36
 
37
37
  single_logout_services.each do |slo|
38
- slo.build(builder, 'SingleLogoutService')
38
+ slo.build(builder, "SingleLogoutService")
39
39
  end
40
40
  name_id_formats.each do |nif|
41
- builder['md'].NameIDFormat(nif)
41
+ builder["md"].NameIDFormat(nif)
42
42
  end
43
43
  end
44
44
  end
data/lib/saml2/status.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/base'
3
+ require "saml2/base"
4
4
 
5
5
  module SAML2
6
6
  class Status < Base
@@ -12,14 +12,16 @@ module SAML2
12
12
  # @param code [String]
13
13
  # @param message [String, nil]
14
14
  def initialize(code = SUCCESS, message = nil)
15
- @code, @message = code, message
15
+ super()
16
+ @code = code
17
+ @message = message
16
18
  end
17
19
 
18
20
  # (see Base#from_xml)
19
21
  def from_xml(node)
20
22
  super
21
- self.code = node.at_xpath('samlp:StatusCode', Namespaces::ALL)['Value']
22
- self.message = load_string_array(xml, 'samlp:StatusMessage')
23
+ self.code = node.at_xpath("samlp:StatusCode", Namespaces::ALL)["Value"]
24
+ self.message = load_string_array(xml, "samlp:StatusMessage")
23
25
  end
24
26
 
25
27
  def success?
@@ -28,10 +30,10 @@ module SAML2
28
30
 
29
31
  # (see Base#build)
30
32
  def build(builder)
31
- builder['samlp'].Status do |status|
32
- status['samlp'].StatusCode(Value: code)
33
+ builder["samlp"].Status do |status|
34
+ status["samlp"].StatusCode(Value: code)
33
35
  Array(message).each do |m|
34
- status['samlp'].StatusMessage(m)
36
+ status["samlp"].StatusMessage(m)
35
37
  end
36
38
  end
37
39
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/message'
4
- require 'saml2/status'
3
+ require "saml2/message"
4
+ require "saml2/status"
5
5
 
6
6
  module SAML2
7
7
  class StatusResponse < Message
@@ -19,12 +19,12 @@ module SAML2
19
19
  super
20
20
  @status = nil
21
21
  remove_instance_variable(:@status)
22
- @in_response_to = node['InResponseTo']
22
+ @in_response_to = node["InResponseTo"]
23
23
  end
24
24
 
25
25
  # @return [Status]
26
26
  def status
27
- @status ||= Status.from_xml(xml.at_xpath('samlp:Status', Namespaces::ALL))
27
+ @status ||= Status.from_xml(xml.at_xpath("samlp:Status", Namespaces::ALL))
28
28
  end
29
29
 
30
30
  protected
@@ -32,7 +32,7 @@ module SAML2
32
32
  def build(status_response)
33
33
  super(status_response)
34
34
 
35
- status_response.parent['InResponseTo'] = in_response_to if in_response_to
35
+ status_response.parent["InResponseTo"] = in_response_to if in_response_to
36
36
 
37
37
  status.build(status_response)
38
38
  end
data/lib/saml2/subject.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/name_id'
4
- require 'saml2/namespaces'
3
+ require "saml2/name_id"
4
+ require "saml2/namespaces"
5
5
 
6
6
  module SAML2
7
7
  class Subject < Base
8
- attr_writer :name_id
9
- attr_writer :confirmations
8
+ attr_writer :name_id, :confirmations
10
9
 
11
10
  def initialize
11
+ super
12
12
  @confirmations = []
13
13
  end
14
14
 
@@ -21,7 +21,7 @@ module SAML2
21
21
  # @return [NameID]
22
22
  def name_id
23
23
  if xml && !instance_variable_defined?(:@name_id)
24
- @name_id = NameID.from_xml(xml.at_xpath('saml:NameID', Namespaces::ALL))
24
+ @name_id = NameID.from_xml(xml.at_xpath("saml:NameID", Namespaces::ALL))
25
25
  end
26
26
  @name_id
27
27
  end
@@ -39,13 +39,13 @@ module SAML2
39
39
 
40
40
  # @return [Confirmation, Array<Confirmation>]
41
41
  def confirmations
42
- @confirmations ||= load_object_array(xml, 'saml:SubjectConfirmation', Confirmation)
42
+ @confirmations ||= load_object_array(xml, "saml:SubjectConfirmation", Confirmation)
43
43
  end
44
44
 
45
45
  # (see Base#build)
46
46
  def build(builder)
47
- builder['saml'].Subject do |subject|
48
- name_id.build(subject) if name_id
47
+ builder["saml"].Subject do |subject|
48
+ name_id&.build(subject)
49
49
  Array(confirmations).each do |confirmation|
50
50
  confirmation.build(subject)
51
51
  end
@@ -54,9 +54,9 @@ module SAML2
54
54
 
55
55
  class Confirmation < Base
56
56
  module Methods
57
- BEARER = 'urn:oasis:names:tc:SAML:2.0:cm:bearer'
58
- HOLDER_OF_KEY = 'urn:oasis:names:tc:SAML:2.0:cm:holder-of-key'
59
- SENDER_VOUCHES = 'urn:oasis:names:tc:SAML:2.0:cm:sender-vouches'
57
+ BEARER = "urn:oasis:names:tc:SAML:2.0:cm:bearer"
58
+ HOLDER_OF_KEY = "urn:oasis:names:tc:SAML:2.0:cm:holder-of-key"
59
+ SENDER_VOUCHES = "urn:oasis:names:tc:SAML:2.0:cm:sender-vouches"
60
60
  end
61
61
 
62
62
  # @see Methods
@@ -70,28 +70,28 @@ module SAML2
70
70
  # (see Base#from_xml)
71
71
  def from_xml(node)
72
72
  super
73
- self.method = node['Method']
74
- confirmation_data = node.at_xpath('saml:SubjectConfirmationData', Namespaces::ALL)
75
- if confirmation_data
76
- self.not_before = Time.parse(confirmation_data['NotBefore']) if confirmation_data['NotBefore']
77
- self.not_on_or_after = Time.parse(confirmation_data['NotOnOrAfter']) if confirmation_data['NotOnOrAfter']
78
- self.recipient = confirmation_data['Recipient']
79
- self.in_response_to = confirmation_data['InResponseTo']
80
- end
73
+ self.method = node["Method"]
74
+ confirmation_data = node.at_xpath("saml:SubjectConfirmationData", Namespaces::ALL)
75
+ return unless confirmation_data
76
+
77
+ self.not_before = Time.parse(confirmation_data["NotBefore"]) if confirmation_data["NotBefore"]
78
+ self.not_on_or_after = Time.parse(confirmation_data["NotOnOrAfter"]) if confirmation_data["NotOnOrAfter"]
79
+ self.recipient = confirmation_data["Recipient"]
80
+ self.in_response_to = confirmation_data["InResponseTo"]
81
81
  end
82
82
 
83
83
  # (see Base#build)
84
84
  def build(builder)
85
- builder['saml'].SubjectConfirmation('Method' => method) do |subject_confirmation|
85
+ builder["saml"].SubjectConfirmation("Method" => method) do |subject_confirmation|
86
86
  if in_response_to ||
87
- recipient ||
88
- not_before ||
89
- not_on_or_after
90
- subject_confirmation['saml'].SubjectConfirmationData do |subject_confirmation_data|
91
- subject_confirmation_data.parent['NotBefore'] = not_before.iso8601 if not_before
92
- subject_confirmation_data.parent['NotOnOrAfter'] = not_on_or_after.iso8601 if not_on_or_after
93
- subject_confirmation_data.parent['Recipient'] = recipient if recipient
94
- subject_confirmation_data.parent['InResponseTo'] = in_response_to if in_response_to
87
+ recipient ||
88
+ not_before ||
89
+ not_on_or_after
90
+ subject_confirmation["saml"].SubjectConfirmationData do |subject_confirmation_data|
91
+ subject_confirmation_data.parent["NotBefore"] = not_before.iso8601 if not_before
92
+ subject_confirmation_data.parent["NotOnOrAfter"] = not_on_or_after.iso8601 if not_on_or_after
93
+ subject_confirmation_data.parent["Recipient"] = recipient if recipient
94
+ subject_confirmation_data.parent["InResponseTo"] = in_response_to if in_response_to
95
95
  end
96
96
  end
97
97
  end
data/lib/saml2/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SAML2
4
- VERSION = '3.1.2'
4
+ VERSION = "3.1.4"
5
5
  end
data/lib/saml2.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/authn_request'
4
- require 'saml2/entity'
5
- require 'saml2/logout_request'
6
- require 'saml2/logout_response'
7
- require 'saml2/response'
8
- require 'saml2/version'
3
+ require "saml2/authn_request"
4
+ require "saml2/entity"
5
+ require "saml2/logout_request"
6
+ require "saml2/logout_response"
7
+ require "saml2/response"
8
+ require "saml2/version"
9
9
 
10
- require 'saml2/engine' if defined?(::Rails) && Rails::VERSION::MAJOR > 2
10
+ require "saml2/engine" if defined?(Rails) && Rails::VERSION::MAJOR > 2
11
11
 
12
12
  module SAML2
13
13
  class << self