Commit a5952bc
Changed files (3)
lib
saml
kit
locales
spec
saml
lib/saml/kit/locales/en.yml
@@ -28,6 +28,7 @@ en:
unregistered: "must originate from registered identity provider."
Signature:
digest_value: "is invalid."
+ empty: "is missing."
SPSSODescriptor:
invalid: "must contain SPSSODescriptor."
invalid_signature: "invalid signature."
lib/saml/kit/signature.rb
@@ -9,24 +9,25 @@ module Saml
attr_reader :name
- def initialize(xml_hash)
+ def initialize(item)
@name = "Signature"
- if xml_hash.is_a?(Hash)
- @xml_hash = xml_hash
+ if item.is_a?(Hash)
+ @xml_hash = item
else
- @document = xml_hash
+ @node = item
end
end
# Returns the embedded X509 Certificate
def certificate
- if @document
- item = @document.at_xpath("//ds:KeyInfo/ds:X509Data/ds:X509Certificate", "ds": ::Xml::Kit::Namespaces::XMLDSIG)
- ::Xml::Kit::Certificate.new(item.text, use: :signing)
- else
+ if @xml_hash
value = to_h.fetch('KeyInfo', {}).fetch('X509Data', {}).fetch('X509Certificate', nil)
return if value.nil?
::Xml::Kit::Certificate.new(value, use: :signing)
+ else
+ return if @node.nil?
+ item = @node.at_xpath("//ds:KeyInfo/ds:X509Data/ds:X509Certificate", "ds": ::Xml::Kit::Namespaces::XMLDSIG)
+ ::Xml::Kit::Certificate.new(item.text, use: :signing)
end
end
@@ -44,9 +45,9 @@ module Saml
private
def validate_signature
- return errors[:base].push("is missing") if certificate.nil?
+ return errors[:base].push(error_message(:empty)) if certificate.nil?
- signature = Xmldsig::Signature.new(@document, 'ID=$uri or @Id')
+ signature = Xmldsig::Signature.new(@node, 'ID=$uri or @Id')
unless signature.valid?(certificate.x509)
signature.errors.each do |attribute|
errors.add(attribute, error_message(attribute))
spec/saml/signature_spec.rb
@@ -19,10 +19,46 @@ RSpec.describe Saml::Kit::Signature do
end
it 'is invalid when the signature is missing' do
- unsigned_document = Saml::Kit::AuthenticationRequest.build
- subject = described_class.new(Hash.from_xml(unsigned_document.to_xml))
+ subject = described_class.new(nil)
expect(subject).to_not be_valid
- expect(subject.errors[:base]).to be_present
+ expect(subject.errors[:base]).to match_array(['is missing.'])
+ end
+
+ describe "certificate validation" do
+ let(:key_pair) { ::Xml::Kit::KeyPair.new(expired_certificate, private_key, nil, :signing) }
+ let(:private_key) { OpenSSL::PKey::RSA.new(2048) }
+ let(:expired_certificate) do
+ certificate = OpenSSL::X509::Certificate.new
+ certificate.not_before = not_before
+ certificate.not_after = not_after
+ certificate.public_key = private_key.public_key
+ certificate.sign(private_key, OpenSSL::Digest::SHA256.new)
+ certificate
+ end
+
+ context "when the certificate is expired" do
+ let(:not_before) { 10.minutes.ago }
+ let(:not_after) { 1.minute.ago }
+
+ it 'is invalid' do
+ expect(subject).to be_invalid
+ expect(subject.errors[:certificate]).to match_array([
+ "Not valid before #{expired_certificate.not_before}. Not valid after #{expired_certificate.not_after}."
+ ])
+ end
+ end
+
+ context "when the certificate is not active yet" do
+ let(:not_before) { 10.minutes.from_now }
+ let(:not_after) { 20.minute.from_now }
+
+ it 'it invalid' do
+ expect(subject).to be_invalid
+ expect(subject.errors[:certificate]).to match_array([
+ "Not valid before #{expired_certificate.not_before}. Not valid after #{expired_certificate.not_after}."
+ ])
+ end
+ end
end
end
end