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,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/core_ext/array/wrap'
3
+ require "active_support/core_ext/array/wrap"
4
4
 
5
5
  module SAML2
6
6
  class Conditions < Array
@@ -12,6 +12,7 @@ module SAML2
12
12
  # (see Base.from_xml)
13
13
  def self.from_xml(node)
14
14
  return nil unless node
15
+
15
16
  result = new
16
17
  result.from_xml(node)
17
18
  result
@@ -20,15 +21,15 @@ module SAML2
20
21
  # (see Base#from_xml)
21
22
  def from_xml(node)
22
23
  @xml = node
23
- @not_before = Time.parse(node['NotBefore']) if node['NotBefore']
24
- @not_on_or_after = Time.parse(node['NotOnOrAfter']) if node['NotOnOrAfter']
24
+ @not_before = Time.parse(node["NotBefore"]) if node["NotBefore"]
25
+ @not_on_or_after = Time.parse(node["NotOnOrAfter"]) if node["NotOnOrAfter"]
25
26
 
26
27
  replace(node.element_children.map do |restriction|
27
28
  klass = if self.class.const_defined?(restriction.name, false)
28
- self.class.const_get(restriction.name, false)
29
- else
30
- Condition
31
- end
29
+ self.class.const_get(restriction.name, false)
30
+ else
31
+ Condition
32
+ end
32
33
  klass.from_xml(restriction)
33
34
  end)
34
35
  end
@@ -67,9 +68,9 @@ module SAML2
67
68
 
68
69
  # (see Base#build)
69
70
  def build(builder)
70
- builder['saml'].Conditions do |conditions|
71
- conditions.parent['NotBefore'] = not_before.iso8601 if not_before
72
- conditions.parent['NotOnOrAfter'] = not_on_or_after.iso8601 if not_on_or_after
71
+ builder["saml"].Conditions do |conditions|
72
+ conditions.parent["NotBefore"] = not_before.iso8601 if not_before
73
+ conditions.parent["NotOnOrAfter"] = not_on_or_after.iso8601 if not_on_or_after
73
74
 
74
75
  each do |condition|
75
76
  condition.build(conditions)
@@ -81,7 +82,7 @@ module SAML2
81
82
  class Condition < Base
82
83
  # @return []
83
84
  def validate(_)
84
- ["unable to validate #{xml&.name || 'unrecognized'} condition"]
85
+ ["unable to validate #{xml&.name || "unrecognized"} condition"]
85
86
  end
86
87
 
87
88
  def valid?(*args)
@@ -94,6 +95,7 @@ module SAML2
94
95
 
95
96
  # @param audience [Array<String>]
96
97
  def initialize(audience = [])
98
+ super()
97
99
  @audience = audience
98
100
  end
99
101
 
@@ -105,7 +107,7 @@ module SAML2
105
107
 
106
108
  # @return [Array<String>] Allowed audiences
107
109
  def audience
108
- @audience ||= load_string_array(xml, 'saml:Audience')
110
+ @audience ||= load_string_array(xml, "saml:Audience")
109
111
  end
110
112
 
111
113
  # @param audience [String]
@@ -113,16 +115,17 @@ module SAML2
113
115
  return [] if ignore_audience_condition
114
116
 
115
117
  unless Array.wrap(self.audience).include?(audience)
116
- return ["audience #{audience} not in allowed list of #{Array.wrap(self.audience).join(', ')}"]
118
+ return ["audience #{audience} not in allowed list of #{Array.wrap(self.audience).join(", ")}"]
117
119
  end
120
+
118
121
  []
119
122
  end
120
123
 
121
124
  # (see Base#build)
122
125
  def build(builder)
123
- builder['saml'].AudienceRestriction do |audience_restriction|
126
+ builder["saml"].AudienceRestriction do |audience_restriction|
124
127
  Array.wrap(audience).each do |single_audience|
125
- audience_restriction['saml'].Audience(single_audience)
128
+ audience_restriction["saml"].Audience(single_audience)
126
129
  end
127
130
  end
128
131
  end
@@ -138,7 +141,7 @@ module SAML2
138
141
 
139
142
  # (see Base#build)
140
143
  def build(builder)
141
- builder['saml'].OneTimeUse
144
+ builder["saml"].OneTimeUse
142
145
  end
143
146
  end
144
147
  end
data/lib/saml2/contact.rb CHANGED
@@ -1,15 +1,15 @@
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 Contact < Base
7
7
  module Type
8
- ADMINISTRATIVE = 'administrative'
9
- BILLING = 'billing'
10
- OTHER = 'other'
11
- SUPPORT = 'support'
12
- TECHNICAL = 'technical'
8
+ ADMINISTRATIVE = "administrative"
9
+ BILLING = "billing"
10
+ OTHER = "other"
11
+ SUPPORT = "support"
12
+ TECHNICAL = "technical"
13
13
  end
14
14
 
15
15
  # @see Type
@@ -22,6 +22,7 @@ module SAML2
22
22
 
23
23
  # @param type [String]
24
24
  def initialize(type = Type::OTHER)
25
+ super()
25
26
  @type = type
26
27
  @email_addresses = []
27
28
  @telephone_numbers = []
@@ -29,29 +30,29 @@ module SAML2
29
30
 
30
31
  # (see Base#from_xml)
31
32
  def from_xml(node)
32
- self.type = node['contactType']
33
- company = node.at_xpath('md:Company', Namespaces::ALL)
33
+ self.type = node["contactType"]
34
+ company = node.at_xpath("md:Company", Namespaces::ALL)
34
35
  self.company = company && company.content && company.content.strip
35
- given_name = node.at_xpath('md:GivenName', Namespaces::ALL)
36
+ given_name = node.at_xpath("md:GivenName", Namespaces::ALL)
36
37
  self.given_name = given_name && given_name.content && given_name.content.strip
37
- surname = node.at_xpath('md:SurName', Namespaces::ALL)
38
+ surname = node.at_xpath("md:SurName", Namespaces::ALL)
38
39
  self.surname = surname && surname.content && surname.content.strip
39
- self.email_addresses = load_string_array(node, 'md:EmailAddress')
40
- self.telephone_numbers = load_string_array(node, 'md:TelephoneNumber')
40
+ self.email_addresses = load_string_array(node, "md:EmailAddress")
41
+ self.telephone_numbers = load_string_array(node, "md:TelephoneNumber")
41
42
  self
42
43
  end
43
44
 
44
45
  # (see Base#build)
45
46
  def build(builder)
46
- builder['md'].ContactPerson('contactType' => type) do |contact_person|
47
- contact_person['md'].Company(company) if company
48
- contact_person['md'].GivenName(given_name) if given_name
49
- contact_person['md'].SurName(surname) if surname
47
+ builder["md"].ContactPerson("contactType" => type) do |contact_person|
48
+ contact_person["md"].Company(company) if company
49
+ contact_person["md"].GivenName(given_name) if given_name
50
+ contact_person["md"].SurName(surname) if surname
50
51
  email_addresses.each do |email|
51
- contact_person['md'].EmailAddress(email)
52
+ contact_person["md"].EmailAddress(email)
52
53
  end
53
54
  telephone_numbers.each do |tel|
54
- contact_person['md'].TelephoneNumber(tel)
55
+ contact_person["md"].TelephoneNumber(tel)
55
56
  end
56
57
  end
57
58
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/bindings/http_post'
3
+ require "saml2/bindings/http_post"
4
4
 
5
5
  module SAML2
6
6
  class Endpoint < Base
@@ -10,25 +10,27 @@ module SAML2
10
10
  # @param location [String]
11
11
  # @param binding [String]
12
12
  def initialize(location = nil, binding = Bindings::HTTP_POST::URN)
13
- @location, @binding = location, binding
13
+ super()
14
+ @location = location
15
+ @binding = binding
14
16
  end
15
17
 
16
18
  # @param rhs [Endpoint]
17
19
  # @return [Boolean]
18
- def ==(rhs)
19
- location == rhs.location && binding == rhs.binding
20
+ def ==(other)
21
+ location == other.location && binding == other.binding
20
22
  end
21
23
 
22
24
  # (see Base#from_xml)
23
25
  def from_xml(node)
24
26
  super
25
- @location = node['Location']
26
- @binding = node['Binding']
27
+ @location = node["Location"]
28
+ @binding = node["Binding"]
27
29
  end
28
30
 
29
31
  # (see Base#build)
30
32
  def build(builder, element)
31
- builder['md'].__send__(element, 'Location' => location, 'Binding' => binding)
33
+ builder["md"].__send__(element, "Location" => location, "Binding" => binding)
32
34
  end
33
35
 
34
36
  class Indexed < Endpoint
@@ -40,12 +42,13 @@ module SAML2
40
42
  # @param binding [String]
41
43
  def initialize(location = nil, index = nil, is_default = nil, binding = Bindings::HTTP_POST::URN)
42
44
  super(location, binding)
43
- @index, @is_default = index, is_default
45
+ @index = index
46
+ @is_default = is_default
44
47
  end
45
48
 
46
- def eql?(rhs)
47
- location == rhs.location &&
48
- binding == rhs.binding && super
49
+ def eql?(other)
50
+ location == other.location &&
51
+ binding == other.binding && super
49
52
  end
50
53
  end
51
54
  end
data/lib/saml2/entity.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'nokogiri'
3
+ require "nokogiri"
4
4
 
5
- require 'saml2/base'
6
- require 'saml2/identity_provider'
7
- require 'saml2/organization_and_contacts'
8
- require 'saml2/service_provider'
9
- require 'saml2/signable'
5
+ require "saml2/base"
6
+ require "saml2/identity_provider"
7
+ require "saml2/organization_and_contacts"
8
+ require "saml2/service_provider"
9
+ require "saml2/signable"
10
10
 
11
11
  module SAML2
12
12
  class Entity < Base
@@ -39,15 +39,16 @@ module SAML2
39
39
  include Enumerable
40
40
  include Signable
41
41
 
42
- [:each, :[]].each do |method|
42
+ %i[each \[\]].each do |method|
43
43
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
44
- def #{method}(*args, &block)
45
- @entities.#{method}(*args, &block)
46
- end
44
+ def #{method}(*args, &block) # def each(*args, &block)
45
+ @entities.#{method}(*args, &block) # @entities.each(*args, &block)
46
+ end # end
47
47
  RUBY
48
48
  end
49
49
 
50
50
  def initialize
51
+ super
51
52
  @entities = []
52
53
  @id = "_#{SecureRandom.uuid}"
53
54
  @valid_until = nil
@@ -58,9 +59,10 @@ module SAML2
58
59
  super
59
60
  @id = nil
60
61
  remove_instance_variable(:@valid_until)
61
- @entities = Base.load_object_array(xml, "md:EntityDescriptor|md:EntitiesDescriptor",
62
- 'EntityDescriptor' => Entity,
63
- 'EntitiesDescriptor' => Group)
62
+ @entities = Base.load_object_array(xml,
63
+ "md:EntityDescriptor|md:EntitiesDescriptor",
64
+ "EntityDescriptor" => Entity,
65
+ "EntitiesDescriptor" => Group)
64
66
  end
65
67
 
66
68
  # (see Message#valid_schema?)
@@ -70,13 +72,13 @@ module SAML2
70
72
 
71
73
  # (see Message#id)
72
74
  def id
73
- @id ||= xml['ID']
75
+ @id ||= xml["ID"]
74
76
  end
75
77
 
76
78
  # @return [Time, nil]
77
79
  def valid_until
78
80
  unless instance_variable_defined?(:@valid_until)
79
- @valid_until = xml['validUntil'] && Time.parse(xml['validUntil'])
81
+ @valid_until = xml["validUntil"] && Time.parse(xml["validUntil"])
80
82
  end
81
83
  @valid_until
82
84
  end
@@ -106,19 +108,17 @@ module SAML2
106
108
 
107
109
  # @return [String]
108
110
  def entity_id
109
- @entity_id || xml && xml['entityID']
111
+ @entity_id || (xml && xml["entityID"])
110
112
  end
111
113
 
112
114
  # (see Message#id)
113
115
  def id
114
- @id ||= xml['ID']
116
+ @id ||= xml["ID"]
115
117
  end
116
118
 
117
119
  # @return [Time, nil]
118
120
  def valid_until
119
- unless instance_variable_defined?(:@valid_until)
120
- @valid_until = xml['validUntil'] && Time.parse(xml['validUntil'])
121
- end
121
+ @valid_until = xml["validUntil"] && Time.parse(xml["validUntil"]) unless instance_variable_defined?(:@valid_until)
122
122
  @valid_until
123
123
  end
124
124
 
@@ -134,17 +134,17 @@ module SAML2
134
134
 
135
135
  # @return [Array<Role>]
136
136
  def roles
137
- @roles ||= load_object_array(xml, 'md:IDPSSODescriptor', IdentityProvider) +
138
- load_object_array(xml, 'md:SPSSODescriptor', ServiceProvider)
137
+ @roles ||= load_object_array(xml, "md:IDPSSODescriptor", IdentityProvider) +
138
+ load_object_array(xml, "md:SPSSODescriptor", ServiceProvider)
139
139
  end
140
140
 
141
141
  # (see Base#build)
142
142
  def build(builder)
143
- builder['md'].EntityDescriptor('entityID' => entity_id,
144
- 'xmlns:md' => Namespaces::METADATA,
145
- 'xmlns:dsig' => Namespaces::DSIG,
146
- 'xmlns:xenc' => Namespaces::XENC) do |entity_descriptor|
147
- entity_descriptor.parent['ID'] = id if id
143
+ builder["md"].EntityDescriptor("entityID" => entity_id,
144
+ "xmlns:md" => Namespaces::METADATA,
145
+ "xmlns:dsig" => Namespaces::DSIG,
146
+ "xmlns:xenc" => Namespaces::XENC) do |entity_descriptor|
147
+ entity_descriptor.parent["ID"] = id if id
148
148
 
149
149
  roles.each do |role|
150
150
  role.build(entity_descriptor)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'saml2/attribute'
4
- require 'saml2/sso'
3
+ require "saml2/attribute"
4
+ require "saml2/sso"
5
5
 
6
6
  module SAML2
7
7
  class IdentityProvider < SSO
@@ -29,39 +29,42 @@ module SAML2
29
29
  # @return [Boolean, nil]
30
30
  def want_authn_requests_signed?
31
31
  unless instance_variable_defined?(:@want_authn_requests_signed)
32
- @want_authn_requests_signed = xml['WantAuthnRequestsSigned'] && xml['WantAuthnRequestsSigned'] == 'true'
32
+ @want_authn_requests_signed = xml["WantAuthnRequestsSigned"] && xml["WantAuthnRequestsSigned"] == "true"
33
33
  end
34
34
  @want_authn_requests_signed
35
35
  end
36
36
 
37
37
  # @return [Array<Endpoint>]
38
38
  def single_sign_on_services
39
- @single_sign_on_services ||= load_object_array(xml, 'md:SingleSignOnService', Endpoint)
39
+ @single_sign_on_services ||= load_object_array(xml, "md:SingleSignOnService", Endpoint)
40
40
  end
41
41
 
42
42
  # @return [Array<String>]
43
43
  def attribute_profiles
44
- @attribute_profiles ||= load_string_array(xml, 'md:AttributeProfile')
44
+ @attribute_profiles ||= load_string_array(xml, "md:AttributeProfile")
45
45
  end
46
46
 
47
47
  # @return [Array<Attribute>]
48
48
  def attributes
49
- @attributes ||= load_object_array(xml, 'saml:Attribute', Attribute)
49
+ @attributes ||= load_object_array(xml, "saml:Attribute", Attribute)
50
50
  end
51
51
 
52
52
  # (see Base#build)
53
53
  def build(builder)
54
- builder['md'].IDPSSODescriptor do |idp_sso_descriptor|
54
+ builder["md"].IDPSSODescriptor do |idp_sso_descriptor|
55
55
  super(idp_sso_descriptor)
56
56
 
57
- idp_sso_descriptor.parent['WantAuthnRequestsSigned'] = want_authn_requests_signed? unless want_authn_requests_signed?.nil?
57
+ unless want_authn_requests_signed?.nil?
58
+ idp_sso_descriptor.parent["WantAuthnRequestsSigned"] =
59
+ want_authn_requests_signed?
60
+ end
58
61
 
59
62
  single_sign_on_services.each do |sso|
60
- sso.build(idp_sso_descriptor, 'SingleSignOnService')
63
+ sso.build(idp_sso_descriptor, "SingleSignOnService")
61
64
  end
62
65
 
63
66
  attribute_profiles.each do |ap|
64
- idp_sso_descriptor['md'].AttributeProfile(ap)
67
+ idp_sso_descriptor["md"].AttributeProfile(ap)
65
68
  end
66
69
 
67
70
  attributes.each do |attr|
@@ -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
  module IndexedObject
@@ -12,9 +12,9 @@ module SAML2
12
12
  super
13
13
  end
14
14
 
15
- def eql?(rhs)
16
- index == rhs.index &&
17
- default? == rhs.default? &&
15
+ def eql?(other)
16
+ index == other.index &&
17
+ default? == other.default? &&
18
18
  super
19
19
  end
20
20
 
@@ -28,8 +28,8 @@ module SAML2
28
28
 
29
29
  # (see Base#from_xml)
30
30
  def from_xml(node)
31
- @index = node['index'] && node['index'].to_i
32
- @is_default = node['isDefault'] && node['isDefault'] == 'true'
31
+ @index = node["index"]&.to_i
32
+ @is_default = node["isDefault"] && node["isDefault"] == "true"
33
33
  super
34
34
  end
35
35
 
@@ -41,10 +41,15 @@ module SAML2
41
41
  attr_reader :default
42
42
 
43
43
  def self.from_xml(nodes)
44
- new(nodes.map { |node| name.split('::')[1..-2].inject(SAML2) { |mod, klass| mod.const_get(klass) }.from_xml(node) }).freeze
44
+ new(nodes.map do |node|
45
+ name.split("::")[1..-2].inject(SAML2) do |mod, klass|
46
+ mod.const_get(klass)
47
+ end.from_xml(node)
48
+ end).freeze
45
49
  end
46
50
 
47
51
  def initialize(objects = nil)
52
+ super()
48
53
  replace(objects.sort_by { |object| object.index || 0 }) if objects
49
54
  re_index
50
55
  end
@@ -72,19 +77,17 @@ module SAML2
72
77
  last_index = object.index
73
78
  @index[object.index] = object
74
79
  end
75
- @default = find { |object| object.default? } || first
80
+ @default = find(&:default?) || first
76
81
  end
77
82
  end
78
83
 
79
84
  # (see Base#build)
80
85
  def build(builder, *)
81
86
  super
82
- builder.parent.children.last['index'] = index
83
- builder.parent.children.last['isDefault'] = default? if default_defined?
87
+ builder.parent.children.last["index"] = index
88
+ builder.parent.children.last["isDefault"] = default? if default_defined?
84
89
  end
85
90
 
86
- private
87
-
88
91
  def self.included(klass)
89
92
  klass.const_set(:Array, Array.dup)
90
93
  end
data/lib/saml2/key.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'openssl'
3
+ require "openssl"
4
4
 
5
- require 'saml2/base'
6
- require 'saml2/namespaces'
5
+ require "saml2/base"
6
+ require "saml2/namespaces"
7
7
 
8
8
  module SAML2
9
9
  # This represents the XML Signatures <KeyInfo> element, and actually contains a
@@ -16,20 +16,21 @@ module SAML2
16
16
 
17
17
  # @param x509 [String] The PEM encoded certificate.
18
18
  def initialize(x509 = nil)
19
+ super()
19
20
  self.x509 = x509
20
21
  end
21
22
 
22
23
  # (see Base#from_xml)
23
24
  def from_xml(node)
24
- self.x509 = node.at_xpath('dsig:X509Data/dsig:X509Certificate', Namespaces::ALL)&.content&.strip
25
- if (rsa_key_value = node.at_xpath('dsig:KeyValue/dsig:RSAKeyValue', Namespaces::ALL))
26
- modulus = crypto_binary_to_integer(rsa_key_value.at_xpath('dsig:Modulus', Namespaces::ALL)&.content&.strip)
27
- exponent = crypto_binary_to_integer(rsa_key_value.at_xpath('dsig:Exponent', Namespaces::ALL)&.content&.strip)
28
- if modulus && exponent
29
- @key = OpenSSL::PKey::RSA.new
30
- key.set_key(modulus, exponent, nil)
31
- end
32
- end
25
+ self.x509 = node.at_xpath("dsig:X509Data/dsig:X509Certificate", Namespaces::ALL)&.content&.strip
26
+ return unless (rsa_key_value = node.at_xpath("dsig:KeyValue/dsig:RSAKeyValue", Namespaces::ALL))
27
+
28
+ modulus = crypto_binary_to_integer(rsa_key_value.at_xpath("dsig:Modulus", Namespaces::ALL)&.content&.strip)
29
+ exponent = crypto_binary_to_integer(rsa_key_value.at_xpath("dsig:Exponent", Namespaces::ALL)&.content&.strip)
30
+ return unless modulus && exponent
31
+
32
+ @key = OpenSSL::PKey::RSA.new
33
+ key.set_key(modulus, exponent, nil)
33
34
  end
34
35
 
35
36
  def x509=(value)
@@ -39,6 +40,7 @@ module SAML2
39
40
  # @return [OpenSSL::X509::Certificate]
40
41
  def certificate
41
42
  return nil if x509.nil?
43
+
42
44
  @certificate ||= OpenSSL::X509::Certificate.new(Base64.decode64(x509))
43
45
  end
44
46
 
@@ -52,28 +54,29 @@ module SAML2
52
54
  # @param fingerprint [String]
53
55
  # @return [String]
54
56
  def self.format_fingerprint(fingerprint)
55
- fingerprint.downcase.gsub(/[^0-9a-f]/, '').gsub(/(\h{2})(?=\h)/, '\1:')
57
+ fingerprint.downcase.gsub(/[^0-9a-f]/, "").gsub(/(\h{2})(?=\h)/, '\1:')
56
58
  end
57
59
 
58
60
  # @return [String]
59
61
  def fingerprint
60
62
  return nil unless certificate
63
+
61
64
  @fingerprint ||= self.class.format_fingerprint(Digest::SHA1.hexdigest(certificate.to_der))
62
65
  end
63
66
 
64
67
  # (see Base#build)
65
68
  def build(builder)
66
- builder['dsig'].KeyInfo do |key_info|
69
+ builder["dsig"].KeyInfo do |key_info|
67
70
  if x509
68
- key_info['dsig'].X509Data do |x509_data|
69
- x509_data['dsig'].X509Certificate(x509)
71
+ key_info["dsig"].X509Data do |x509_data|
72
+ x509_data["dsig"].X509Certificate(x509)
70
73
  end
71
74
  end
72
75
  if key.is_a?(OpenSSL::PKey::RSA)
73
- key_info['dsig'].KeyValue do |key_value|
74
- key_value['dsig'].RSAKeyValue do |rsa_key_value|
75
- rsa_key_value['dsig'].Modulus(Base64.encode64(key.n.to_s(2)))
76
- rsa_key_value['dsig'].Exponent(Base64.encode64(key.e.to_s(2)))
76
+ key_info["dsig"].KeyValue do |key_value|
77
+ key_value["dsig"].RSAKeyValue do |rsa_key_value|
78
+ rsa_key_value["dsig"].Modulus(Base64.encode64(key.n.to_s(2)))
79
+ rsa_key_value["dsig"].Exponent(Base64.encode64(key.e.to_s(2)))
77
80
  end
78
81
  end
79
82
  end
@@ -84,19 +87,20 @@ module SAML2
84
87
 
85
88
  def crypto_binary_to_integer(str)
86
89
  return nil unless str
90
+
87
91
  OpenSSL::BN.new(Base64.decode64(str), 2)
88
92
  end
89
93
  end
90
94
 
91
95
  class KeyDescriptor < KeyInfo
92
96
  module Type
93
- ENCRYPTION = 'encryption'
94
- SIGNING = 'signing'
97
+ ENCRYPTION = "encryption"
98
+ SIGNING = "signing"
95
99
  end
96
100
 
97
101
  class EncryptionMethod < Base
98
102
  module Algorithm
99
- AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'
103
+ AES128_CBC = "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
100
104
  end
101
105
 
102
106
  # @see Algorithm
@@ -108,19 +112,21 @@ module SAML2
108
112
  # @param algorithm [String]
109
113
  # @param key_size [Integer]
110
114
  def initialize(algorithm = Algorithm::AES128_CBC, key_size = 128)
111
- @algorithm, @key_size = algorithm, key_size
115
+ super()
116
+ @algorithm = algorithm
117
+ @key_size = key_size
112
118
  end
113
119
 
114
120
  # (see Base#from_xml)
115
121
  def from_xml(node)
116
- self.algorithm = node['Algorithm']
117
- self.key_size = node.at_xpath('xenc:KeySize', Namespaces::ALL)&.content&.to_i
122
+ self.algorithm = node["Algorithm"]
123
+ self.key_size = node.at_xpath("xenc:KeySize", Namespaces::ALL)&.content&.to_i
118
124
  end
119
125
 
120
126
  # (see Base#build)
121
127
  def build(builder)
122
- builder['md'].EncryptionMethod('Algorithm' => algorithm) do |encryption_method|
123
- encryption_method['xenc'].KeySize(key_size) if key_size
128
+ builder["md"].EncryptionMethod("Algorithm" => algorithm) do |encryption_method|
129
+ encryption_method["xenc"].KeySize(key_size) if key_size
124
130
  end
125
131
  end
126
132
  end
@@ -133,16 +139,19 @@ module SAML2
133
139
 
134
140
  # (see Base#from_xml)
135
141
  def from_xml(node)
136
- super(node.at_xpath('dsig:KeyInfo', Namespaces::ALL))
137
- self.use = node['use']
138
- self.encryption_methods = load_object_array(node, 'md:EncryptionMethod', EncryptionMethod)
142
+ super(node.at_xpath("dsig:KeyInfo", Namespaces::ALL))
143
+ self.use = node["use"]
144
+ self.encryption_methods = load_object_array(node, "md:EncryptionMethod", EncryptionMethod)
139
145
  end
140
146
 
141
147
  # @param x509 [String] The PEM encoded certificate.
142
148
  # @param use optional [String] See {Type}
143
149
  # @param encryption_methods [Array<EncryptionMethod>]
144
150
  def initialize(x509 = nil, use = nil, encryption_methods = [])
145
- @use, self.x509, @encryption_methods = use, x509, encryption_methods
151
+ super()
152
+ @use = use
153
+ self.x509 = x509
154
+ @encryption_methods = encryption_methods
146
155
  end
147
156
 
148
157
  def encryption?
@@ -155,8 +164,8 @@ module SAML2
155
164
 
156
165
  # (see Base#build)
157
166
  def build(builder)
158
- builder['md'].KeyDescriptor do |key_descriptor|
159
- key_descriptor.parent['use'] = use if use
167
+ builder["md"].KeyDescriptor do |key_descriptor|
168
+ key_descriptor.parent["use"] = use if use
160
169
  super(key_descriptor)
161
170
  encryption_methods.each do |method|
162
171
  method.build(key_descriptor)