saml2 3.1.2 → 3.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) 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 -137
  43. data/schemas/MetadataExchange.xsd +0 -112
  44. data/schemas/metadata_combined.xsd +0 -13
  45. data/schemas/oasis-200401-wss-wssecurity-secext-1.0.xsd +0 -195
  46. data/schemas/oasis-200401-wss-wssecurity-utility-1.0.xsd +0 -108
  47. data/schemas/saml-schema-assertion-2.0.xsd +0 -283
  48. data/schemas/saml-schema-metadata-2.0.xsd +0 -339
  49. data/schemas/saml-schema-protocol-2.0.xsd +0 -302
  50. data/schemas/sstc-saml-metadata-ext-query.xsd +0 -66
  51. data/schemas/ws-addr.xsd +0 -137
  52. data/schemas/ws-authorization.xsd +0 -145
  53. data/schemas/ws-federation.xsd +0 -471
  54. data/schemas/ws-securitypolicy-1.2.xsd +0 -1205
  55. data/schemas/xenc-schema.xsd +0 -136
  56. data/schemas/xml.xsd +0 -287
  57. data/schemas/xmldsig-core-schema.xsd +0 -309
  58. data/spec/fixtures/FederationMetadata.xml +0 -670
  59. data/spec/fixtures/authnrequest.xml +0 -12
  60. data/spec/fixtures/certificate.pem +0 -24
  61. data/spec/fixtures/entities.xml +0 -13
  62. data/spec/fixtures/external-uri-reference-response.xml +0 -48
  63. data/spec/fixtures/identity_provider.xml +0 -46
  64. data/spec/fixtures/noconditions_response.xml +0 -1
  65. data/spec/fixtures/othercertificate.pem +0 -25
  66. data/spec/fixtures/privatekey.key +0 -27
  67. data/spec/fixtures/response_assertion_signed_reffed_from_response.xml +0 -6
  68. data/spec/fixtures/response_signed.xml +0 -46
  69. data/spec/fixtures/response_tampered_certificate.xml +0 -25
  70. data/spec/fixtures/response_tampered_signature.xml +0 -46
  71. data/spec/fixtures/response_with_attribute_signed.xml +0 -46
  72. data/spec/fixtures/response_with_encrypted_assertion.xml +0 -58
  73. data/spec/fixtures/response_with_rsa_key_value.xml +0 -1
  74. data/spec/fixtures/response_with_signed_assertion_and_encrypted_subject.xml +0 -116
  75. data/spec/fixtures/response_without_keyinfo.xml +0 -1
  76. data/spec/fixtures/service_provider.xml +0 -79
  77. data/spec/fixtures/test3-response.xml +0 -9
  78. data/spec/fixtures/test6-response.xml +0 -10
  79. data/spec/fixtures/test7-response.xml +0 -10
  80. data/spec/fixtures/xml_missigned_assertion.xml +0 -84
  81. data/spec/fixtures/xml_signature_wrapping_attack_duplicate_ids.xml +0 -11
  82. data/spec/fixtures/xml_signature_wrapping_attack_response_attributes.xml +0 -45
  83. data/spec/fixtures/xml_signature_wrapping_attack_response_nameid.xml +0 -44
  84. data/spec/fixtures/xslt-transform-response.xml +0 -57
  85. data/spec/lib/attribute_consuming_service_spec.rb +0 -129
  86. data/spec/lib/attribute_spec.rb +0 -149
  87. data/spec/lib/authn_request_spec.rb +0 -52
  88. data/spec/lib/bindings/http_redirect_spec.rb +0 -183
  89. data/spec/lib/conditions_spec.rb +0 -74
  90. data/spec/lib/entity_spec.rb +0 -58
  91. data/spec/lib/identity_provider_spec.rb +0 -43
  92. data/spec/lib/indexed_object_spec.rb +0 -71
  93. data/spec/lib/key_spec.rb +0 -23
  94. data/spec/lib/logout_request_spec.rb +0 -33
  95. data/spec/lib/logout_response_spec.rb +0 -33
  96. data/spec/lib/message_spec.rb +0 -23
  97. data/spec/lib/response_spec.rb +0 -293
  98. data/spec/lib/service_provider_spec.rb +0 -76
  99. data/spec/lib/signable_spec.rb +0 -15
  100. 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.3"
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