saml2 2.2.12 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 630f03aeb419e5d7ebae94ab4b809bf460be88903fdfdfe981d96dda990fbb5d
4
- data.tar.gz: 2f17e8e081522cf5c7b2e8b5705bf600fd33fbc68e404203f865c442ffeea85c
3
+ metadata.gz: e68ac85048800a528987268cfb09cf9ed3adf9e501e14927969970eba7b48d53
4
+ data.tar.gz: 87edd68a1925ef511840fbff7003cce962ab3fc11bd47e3a9a74cb2300e98136
5
5
  SHA512:
6
- metadata.gz: cad2fd1128ddfa7d8522ca592f8a72b717554ef0d8cddd55b160183e0656df306bebadd0f19e3b131267f8100f1a80ca0956c2c9a78a7eb0e9ad195eb4b72edc
7
- data.tar.gz: d38744fc8b083257306a25b7d3f2e1538313f7791e2667debac3e915499153699ee8af484d6aed2769dc51baffa35e03694759af7e5b32407b77e973b7c66bef
6
+ metadata.gz: 45163bf19f9acbf26223766b165d40d62ad8f0fac6fadad901254912064c56db830c66e27a2e2d85bcd07c2be84c62156df516ae35c028b60b4b4ea692ae2645
7
+ data.tar.gz: 8e7d1b05ea37fc9c39024cfc1c2812170ef09fd4ead00b7b6c174cc9fbf8b0f3e8a8f5c4883ee9257bccfcca79482ffef1d07eac320147f69fed00bd60017480
@@ -119,22 +119,6 @@ module SAML2
119
119
  true
120
120
  end
121
121
 
122
- # (see Signable#validate_signature)
123
- # @param verification_time
124
- # Ignored. The message's {issue_instant} is always used.
125
- def validate_signature(fingerprint: nil,
126
- cert: nil,
127
- verification_time: issue_instant,
128
- allow_expired_certificate: false,
129
- verify_certificate: true)
130
- # verify the signature (certificate's validity) as of the time the message was generated
131
- super(fingerprint: fingerprint,
132
- cert: cert,
133
- verification_time: verification_time,
134
- allow_expired_certificate: allow_expired_certificate,
135
- verify_certificate: verify_certificate)
136
- end
137
-
138
122
  # (see Signable#sign)
139
123
  def sign(x509_certificate, private_key, algorithm_name = :sha256)
140
124
  super
@@ -89,18 +89,11 @@ module SAML2
89
89
  # @param verification_time optional [DateTime]
90
90
  # Validate timestamps (signing certificate validity, issued at, etc.) as of
91
91
  # this point in time.
92
- # @param allow_expired_certificate optional [true, false]
93
- # Allow signing certificate to be expired.
94
- # @param verify_certificate optional [true, false]
95
- # Don't validate the trust chain or validity dates of the signing
96
- # certificate.
97
92
  # @param ignore_audience_condition optional [true, false]
98
93
  # Don't validate any Audience conditions.
99
94
  def validate(service_provider:,
100
95
  identity_provider:,
101
96
  verification_time: nil,
102
- allow_expired_certificate: false,
103
- verify_certificate: true,
104
97
  ignore_audience_condition: false)
105
98
  raise ArgumentError, "service_provider should be an Entity object" unless service_provider.is_a?(Entity)
106
99
  raise ArgumentError, "service_provider should have at least one service_provider role" unless (sp = service_provider.service_providers.first)
@@ -140,9 +133,7 @@ module SAML2
140
133
 
141
134
  if signed?
142
135
  unless (signature_errors = validate_signature(fingerprint: idp.fingerprints,
143
- cert: certificates,
144
- allow_expired_certificate: allow_expired_certificate,
145
- verify_certificate: verify_certificate)).empty?
136
+ cert: certificates)).empty?
146
137
  return errors.concat(signature_errors)
147
138
  end
148
139
  response_signed = true
@@ -153,9 +144,7 @@ module SAML2
153
144
  # this might be nil, if the assertion was encrypted
154
145
  if assertion&.signed?
155
146
  unless (signature_errors = assertion.validate_signature(fingerprint: idp.fingerprints,
156
- cert: certificates,
157
- allow_expired_certificate: allow_expired_certificate,
158
- verify_certificate: verify_certificate)).empty?
147
+ cert: certificates)).empty?
159
148
  return errors.concat(signature_errors)
160
149
  end
161
150
  assertion_signed = true
@@ -211,9 +200,7 @@ module SAML2
211
200
  # check it now
212
201
  if assertion.signed? && !assertion_signed
213
202
  unless (signature_errors = assertion.validate_signature(fingerprint: idp.fingerprints,
214
- cert: certificates,
215
- allow_expired_certificate: allow_expired_certificate,
216
- verify_certificate: verify_certificate)).empty?
203
+ cert: certificates)).empty?
217
204
  return errors.concat(signature_errors)
218
205
  end
219
206
  assertion_signed = true
@@ -34,24 +34,24 @@ module SAML2
34
34
 
35
35
  # Validate the signature on this object.
36
36
  #
37
- # Either +fingerprint+ or +cert+ must be provided.
37
+ # At least one of +key+, +fingerprint+ or +cert+ must be provided.
38
38
  #
39
+ # @param key optional [String, OpenSSL::PKey::PKey]
40
+ # The exact public key to use. +fingerprint+ and +cert+ are ignored.
39
41
  # @param fingerprint optional [Array<String>, String]
40
42
  # SHA1 fingerprints of trusted certificates. If provided, they will be
41
43
  # checked against the {#signing_key} embedded in the {#signature}, and if
42
44
  # a match is found, the certificate embedded in the signature will be
43
45
  # added to the list of certificates used for verifying the signature.
44
46
  # @param cert optional [Array<String>, String]
45
- # @param allow_expired_certificate [Boolean]
46
- # If set to true, verification_time will be adjusted to be just within the
47
- # certificate's expiration time, so that an expired certificate error will
48
- # not be thrown.
47
+ # A single or array of trusted certificates. If provided, they will be
48
+ # check against the {#signing_key} embedded in the {#signature}, and if
49
+ # a match of public keys only is found, that key will be considered trusted
50
+ # and used to verify the signature.
49
51
  # @return [Array<String>] An empty array on success, details of errors on failure.
50
- def validate_signature(fingerprint: nil,
51
- cert: nil,
52
- verification_time: nil,
53
- allow_expired_certificate: false,
54
- verify_certificate: true)
52
+ def validate_signature(key: nil,
53
+ fingerprint: nil,
54
+ cert: nil)
55
55
  return ["not signed"] unless signed?
56
56
 
57
57
  certs = Array(cert)
@@ -59,39 +59,22 @@ module SAML2
59
59
  # see if any given fingerprints match the certificate embedded in the XML;
60
60
  # if so, extract the certificate, and add it to the allowed certificates list
61
61
  Array(fingerprint).each do |fp|
62
- certs << signing_key.certificate if signing_key&.fingerprint == KeyInfo.format_fingerprint(fp)
62
+ certs << signing_key.certificate if signing_key&.fingerprint == SAML2::KeyInfo.format_fingerprint(fp)
63
63
  end
64
64
  certs = certs.uniq
65
- return ["no trusted certificate found"] if certs.empty?
66
65
 
67
- if verify_certificate == false && signing_key&.certificate
68
- key = signing_key.certificate.public_key.to_s
66
+ trusted_keys = certs.map do |cert|
67
+ cert = cert.is_a?(String) ? OpenSSL::X509::Certificate.new(cert) : cert
68
+ cert.public_key.to_s
69
69
  end
70
-
71
- if signing_key
72
- signing_cert = signing_key.certificate
73
- if allow_expired_certificate
74
- verification_time = signing_cert.not_after - 1
75
- end
76
-
77
- # we explicitly trust the signing certificate, but it's not self-signed;
78
- # xmlsec is weird and decides not to trust it in that case, so we skip
79
- # certificate verification by xmlsec, and do it ourselves
80
- if certs.include?(signing_cert) && signing_cert.issuer != signing_cert.subject
81
- verification_time ||= Time.now.utc
82
- return ["certificate has expired"] if verification_time > signing_cert.not_after
83
- return ["certificate is not yet valid"] if verification_time < signing_cert.not_before
84
-
85
- verify_certificate = false
86
- end
70
+ if signing_key&.certificate && trusted_keys.include?(signing_key.certificate.public_key.to_s)
71
+ key ||= signing_key.certificate.public_key.to_s
87
72
  end
88
- certs = nil if key # we're using a key explicitly, ignoring the certs
73
+
74
+ return ["no trusted signing key found"] if key.nil?
89
75
 
90
76
  begin
91
- result = signature.verify_with(key: key,
92
- certs: certs,
93
- verification_time: verification_time,
94
- verify_certificates: verify_certificate)
77
+ result = signature.verify_with(key: key)
95
78
  result ? [] : ["signature is invalid"]
96
79
  rescue XMLSec::VerificationError => e
97
80
  [e.message]
@@ -104,8 +87,8 @@ module SAML2
104
87
  #
105
88
  # @param (see #validate_signature)
106
89
  # @return [Boolean]
107
- def valid_signature?(fingerprint: nil, cert: nil, verification_time: nil)
108
- validate_signature(fingerprint: fingerprint, cert: cert, verification_time: verification_time).empty?
90
+ def valid_signature?(fingerprint: nil, cert: nil)
91
+ validate_signature(fingerprint: fingerprint, cert: cert).empty?
109
92
  end
110
93
 
111
94
  # Sign this object.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SAML2
4
- VERSION = '2.2.12'
4
+ VERSION = '3.0.0'
5
5
  end
@@ -104,8 +104,7 @@ module SAML2
104
104
 
105
105
  # the signature is still valid (we have to set a weird verification time because the response
106
106
  # was signed with an expired signature)
107
- expect(response.validate_signature(fingerprint: 'afe71c28ef740bc87425be13a2263d37971da1f9',
108
- verification_time: Time.parse("2007-07-14 12:01:34Z"))).to eq []
107
+ expect(response.validate_signature(fingerprint: 'afe71c28ef740bc87425be13a2263d37971da1f9')).to eq []
109
108
 
110
109
  # the comment is ignored, but doesn't truncate the nameid
111
110
  expect(response.assertions.first.subject.name_id.id).to eq 'testuser@example.com'
@@ -175,8 +174,7 @@ module SAML2
175
174
 
176
175
  response = Response.parse(fixture("response_tampered_certificate.xml"))
177
176
  sp_entity.valid_response?(response, idp_entity,
178
- verification_time: Time.parse('2015-02-12T22:51:30Z'),
179
- allow_expired_certificate: true)
177
+ verification_time: Time.parse('2015-02-12T22:51:30Z'))
180
178
  expect(response.errors).to eq ["signature is invalid"]
181
179
  end
182
180
 
@@ -193,7 +191,7 @@ module SAML2
193
191
  idp_entity.identity_providers.first.keys << KeyDescriptor.new(fixture("othercertificate.pem"))
194
192
  sp_entity.valid_response?(response, idp_entity, verification_time: Time.parse('2015-02-12T22:51:30Z'))
195
193
  expect(response.errors.length).to eq 1
196
- expect(response.errors.first).to start_with('error occurred during signature verification')
194
+ expect(response.errors.first).to eq("no trusted signing key found")
197
195
  end
198
196
 
199
197
  it "validates signature by fingerprint" do
@@ -211,7 +209,7 @@ module SAML2
211
209
  idp_entity.identity_providers.first.fingerprints << "1c:37:7d:30:c1:83:18:ea:20:8b:dc:d5:35:b6:16:85:17:58:f7:ca"
212
210
 
213
211
  sp_entity.valid_response?(response, idp_entity, verification_time: Time.parse('2015-02-12T22:51:30Z'))
214
- expect(response.errors).to eq ["no trusted certificate found"]
212
+ expect(response.errors).to eq ["no trusted signing key found"]
215
213
  end
216
214
 
217
215
  it "protects against xml signature wrapping attacks targeting nameid" do
@@ -254,43 +252,6 @@ module SAML2
254
252
  "43:0: ERROR: Element '{http://www.w3.org/2000/09/xmldsig#}Signature': This element is not expected."]
255
253
  end
256
254
 
257
- it "errors on expired certificate" do
258
- response = Response.parse(fixture("test6-response.xml"))
259
- idp_entity.entity_id = 'http://simplesamlphp.dev/simplesaml/saml2/idp/metadata.php'
260
- idp_entity.identity_providers.first.keys.clear
261
- idp_entity.identity_providers.first.fingerprints << "afe71c28ef740bc87425be13a2263d37971da1f9"
262
-
263
- sp_entity.valid_response?(response, idp_entity, verification_time: Time.parse("2012-08-03T20:07:15Z"))
264
- expect(response.errors.length).to eq 1
265
- expect(response.errors.first).to match(/certificate has expired/)
266
- end
267
-
268
- it "ignores expired certificate when requested" do
269
- response = Response.parse(fixture("test6-response.xml"))
270
- sp_entity.entity_id = 'http://shard-2.canvas.dev/saml2'
271
- idp_entity.entity_id = 'http://simplesamlphp.dev/simplesaml/saml2/idp/metadata.php'
272
- idp_entity.identity_providers.first.keys.clear
273
- idp_entity.identity_providers.first.fingerprints << "afe71c28ef740bc87425be13a2263d37971da1f9"
274
-
275
- sp_entity.valid_response?(response, idp_entity,
276
- verification_time: Time.parse("2014-09-16T22:15:53Z"),
277
- allow_expired_certificate: true)
278
- expect(response.errors).to eq []
279
- end
280
-
281
- it "ignores invalid certificate when requested" do
282
- response = Response.parse(fixture("test6-response.xml"))
283
- sp_entity.entity_id = 'http://shard-2.canvas.dev/saml2'
284
- idp_entity.entity_id = 'http://simplesamlphp.dev/simplesaml/saml2/idp/metadata.php'
285
- idp_entity.identity_providers.first.keys.clear
286
- idp_entity.identity_providers.first.fingerprints << "afe71c28ef740bc87425be13a2263d37971da1f9"
287
-
288
- sp_entity.valid_response?(response, idp_entity,
289
- verification_time: Time.parse("2014-09-16T22:15:53Z"),
290
- verify_certificate: false)
291
- expect(response.errors).to eq []
292
- end
293
-
294
255
  it "doesn't break the signature by decrypting elements first" do
295
256
  response = Response.parse(fixture("response_with_signed_assertion_and_encrypted_subject.xml"))
296
257
  sp_entity.valid_response?(response, idp_entity, verification_time: Time.parse('2015-02-12T22:51:30Z'))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saml2
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.12
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-25 00:00:00.000000000 Z
11
+ date: 2018-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri