Module: SAML2::Signable
- Included in:
- Entity, Entity::Group, Message, Role
- Defined in:
- lib/saml2/signable.rb
Instance Method Summary collapse
-
#sign(x509_certificate, private_key, algorithm_name = :sha256) ⇒ self
Sign this object.
- #signature ⇒ Nokogiri::XML::Element?
- #signed? ⇒ Boolean
- #signing_key ⇒ KeyInfo?
-
#valid_signature?(**kwargs) ⇒ Boolean
Check if the signature on this object is valid.
-
#validate_signature(key: nil, fingerprint: nil, cert: nil) ⇒ Array<String>
Validate the signature on this object.
Instance Method Details
#sign(x509_certificate, private_key, algorithm_name = :sha256) ⇒ self
Sign this object.
115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/saml2/signable.rb', line 115 def sign(x509_certificate, private_key, algorithm_name = :sha256) to_xml xml = @document.root xml.set_id_attribute('ID') xml.sign!(cert: x509_certificate, key: private_key, digest_alg: algorithm_name.to_s, signature_alg: "rsa-#{algorithm_name}", uri: "##{id}") # the Signature element must be the first element signature = xml.at_xpath("dsig:Signature", Namespaces::ALL) xml.children.first.add_previous_sibling(signature) self end |
#signature ⇒ Nokogiri::XML::Element?
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/saml2/signable.rb', line 8 def signature unless instance_variable_defined?(:@signature) @signature = xml.xpath('//dsig:Signature', Namespaces::ALL).find do |signature| signed_node = signature.at_xpath('dsig:SignedInfo/dsig:Reference', Namespaces::ALL)['URI'] if signed_node == '' true if xml == xml.document.root elsif signed_node != "##{xml['ID']}" false else # validating the schema will automatically add ID attributes, so check that first xml.set_id_attribute('ID') unless xml.document.get_id(xml['ID']) true end end end @signature end |
#signed? ⇒ Boolean
35 36 37 |
# File 'lib/saml2/signable.rb', line 35 def signed? !!signature end |
#signing_key ⇒ KeyInfo?
27 28 29 30 31 32 33 |
# File 'lib/saml2/signable.rb', line 27 def signing_key unless instance_variable_defined?(:@signing_key) # don't use `... if signature.at_xpath(...)` - we need to make sure we assign the nil @signing_key = (key_info = signature.at_xpath('dsig:KeyInfo', Namespaces::ALL)) ? KeyInfo.from_xml(key_info) : nil end @signing_key end |
#valid_signature?(**kwargs) ⇒ Boolean
Check if the signature on this object is valid.
Either fingerprint
or cert
must be provided.
102 103 104 |
# File 'lib/saml2/signable.rb', line 102 def valid_signature?(**kwargs) validate_signature(**kwargs).empty? end |
#validate_signature(key: nil, fingerprint: nil, cert: nil) ⇒ Array<String>
Validate the signature on this object.
At least one of key
, fingerprint
or cert
must be provided. If the signature doesn’t specify which key to use, the first provided key will be used.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/saml2/signable.rb', line 57 def validate_signature(key: nil, fingerprint: nil, cert: nil) return ["not signed"] unless signed? certs = Array(cert) certs = certs.dup if certs.equal?(cert) # see if any given fingerprints match the certificate embedded in the XML; # if so, extract the certificate, and add it to the allowed certificates list Array(fingerprint).each do |fp| certs << signing_key.certificate if signing_key&.fingerprint == SAML2::KeyInfo.format_fingerprint(fp) end certs = certs.uniq trusted_keys = Array.wrap(key).map(&:to_s) trusted_keys.concat(certs.map do |cert| cert = cert.is_a?(String) ? OpenSSL::X509::Certificate.new(cert) : cert cert.public_key.to_s end) if trusted_keys.include?(signing_key&.public_key&.to_s) verification_key = signing_key.public_key.to_s end # signature doesn't say who signed it. hope and pray it's with the only certificate # we know about if signing_key.nil? verification_key = trusted_keys.first end return ["no trusted signing key found"] if verification_key.nil? begin result = signature.verify_with(key: verification_key) result ? [] : ["signature is invalid"] rescue XMLSec::VerificationError => e [e.] end end |