class Samlr::Signature
A SAML specific implementation en.wikipedia.org/wiki/XML_Signature
Attributes
document[R]
fingerprint[R]
options[R]
original[R]
prefix[R]
signature[R]
Public Class Methods
new(original, prefix, options)
click to toggle source
Is initialized with the source document and a path to the element embedding the signature
# File lib/samlr/signature.rb, line 12 def initialize(original, prefix, options) # Signature validations require document alterations @original = original @document = original.dup @prefix = prefix @options = options if @signature = document.at("#{prefix}/ds:Signature", NS_MAP) @signature.remove # enveloped signatures only end @fingerprint = if options[:fingerprint] Fingerprint.from_string(options[:fingerprint]) elsif options[:certificate] Certificate.new(options[:certificate]).fingerprint end end
Public Instance Methods
missing?()
click to toggle source
# File lib/samlr/signature.rb, line 34 def missing? signature.nil? || certificate.nil? end
present?()
click to toggle source
# File lib/samlr/signature.rb, line 30 def present? !missing? end
references()
click to toggle source
# File lib/samlr/signature.rb, line 48 def references @references ||= [].tap do |refs| original.xpath("#{prefix}/ds:Signature/ds:SignedInfo/ds:Reference[@URI]", NS_MAP).each do |ref| refs << Samlr::Reference.new(ref) end end end
verify!()
click to toggle source
# File lib/samlr/signature.rb, line 38 def verify! raise SignatureError.new("No signature at #{prefix}/ds:Signature") unless present? verify_fingerprint! unless options[:skip_fingerprint] verify_digests! verify_signature! true end
Private Instance Methods
certificate()
click to toggle source
# File lib/samlr/signature.rb, line 113 def certificate @certificate ||= begin if node = certificate_node Certificate.new(Base64.decode64(node.text)) elsif cert = options[:certificate] Certificate.new(cert) else nil end end end
certificate!()
click to toggle source
# File lib/samlr/signature.rb, line 125 def certificate! certificate || raise(SignatureError.new("No X509Certificate element in response signature. Cannot validate signature.")) end
certificate_node()
click to toggle source
# File lib/samlr/signature.rb, line 129 def certificate_node signature.at("./ds:KeyInfo/ds:X509Data/ds:X509Certificate", NS_MAP) end
decoded_signature_value()
click to toggle source
# File lib/samlr/signature.rb, line 109 def decoded_signature_value @decoded_signature_value = Base64.decode64(signature_value) end
referenced_node(id)
click to toggle source
Looks up node by id, checks that there's only a single node with a given id
# File lib/samlr/signature.rb, line 91 def referenced_node(id) nodes = document.xpath("//*[@ID='#{id}']") if nodes.size != 1 raise SignatureError.new("Reference validation error: Invalid element references", "Expected 1 element with id #{id}, found #{nodes.size}") end nodes.first end
signature_method()
click to toggle source
# File lib/samlr/signature.rb, line 101 def signature_method @signature_method ||= Samlr::Tools.algorithm(signature.at("./ds:SignedInfo/ds:SignatureMethod/@Algorithm", NS_MAP).try(:value)) end
signature_value()
click to toggle source
# File lib/samlr/signature.rb, line 105 def signature_value @signature_value ||= signature.at("./ds:SignatureValue", NS_MAP).text end
verify_digests!()
click to toggle source
Tests that the document content has not been edited
# File lib/samlr/signature.rb, line 68 def verify_digests! references.each do |reference| node = referenced_node(reference.uri) canoned = node.canonicalize(C14N, reference.namespaces) digest = reference.digest_method.digest(canoned) if digest != reference.decoded_digest_value raise SignatureError.new("Reference validation error: Digest mismatch for #{reference.uri}") end end end
verify_fingerprint!()
click to toggle source
Establishes trust that the remote party is who you think
# File lib/samlr/signature.rb, line 63 def verify_fingerprint! fingerprint.verify!(certificate!) end
verify_signature!()
click to toggle source
Tests correctness of the signature (and hence digests)
# File lib/samlr/signature.rb, line 81 def verify_signature! node = original.at("#{prefix}/ds:Signature/ds:SignedInfo", NS_MAP) canoned = node.canonicalize(C14N) unless x509.public_key.verify(signature_method.new, decoded_signature_value, canoned) raise SignatureError.new("Signature validation error: Possible canonicalization mismatch", "This canonicalizer returns #{canoned}") end end
x509()
click to toggle source
# File lib/samlr/signature.rb, line 58 def x509 @x509 ||= certificate!.x509 end