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?(fingerprint: nil, cert: nil, verification_time: nil) ⇒ Boolean
Check if the signature on this object is valid.
-
#validate_signature(fingerprint: nil, cert: nil, verification_time: nil, allow_expired_certificate: false, verify_certificate: true) ⇒ Array<String>
Validate the signature on this object.
Instance Method Details
#sign(x509_certificate, private_key, algorithm_name = :sha256) ⇒ self
Sign this object.
120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/saml2/signable.rb', line 120 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.at_xpath('dsig:Signature', Namespaces::ALL) if @signature signed_node = @signature.at_xpath('dsig:SignedInfo/dsig:Reference', Namespaces::ALL)['URI'] if signed_node == '' @signature = nil unless xml == xml.document.root elsif signed_node != "##{xml['ID']}" @signature = nil 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']) end end end @signature end |
#signed? ⇒ Boolean
31 32 33 |
# File 'lib/saml2/signable.rb', line 31 def signed? !!signature end |
#signing_key ⇒ KeyInfo?
27 28 29 |
# File 'lib/saml2/signable.rb', line 27 def signing_key @signing_key ||= KeyInfo.from_xml(signature) end |
#valid_signature?(fingerprint: nil, cert: nil, verification_time: nil) ⇒ Boolean
Check if the signature on this object is valid.
Either fingerprint
or cert
must be provided.
107 108 109 |
# File 'lib/saml2/signable.rb', line 107 def valid_signature?(fingerprint: nil, cert: nil, verification_time: nil) validate_signature(fingerprint: fingerprint, cert: cert, verification_time: verification_time).empty? end |
#validate_signature(fingerprint: nil, cert: nil, verification_time: nil, allow_expired_certificate: false, verify_certificate: true) ⇒ Array<String>
Validate the signature on this object.
Either fingerprint
or cert
must be provided.
50 51 52 53 54 55 56 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 95 96 97 98 99 |
# File 'lib/saml2/signable.rb', line 50 def validate_signature(fingerprint: nil, cert: nil, verification_time: nil, allow_expired_certificate: false, verify_certificate: true) 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 == KeyInfo.format_fingerprint(fp) end certs = certs.uniq return ["no trusted certificate found"] if certs.empty? if verify_certificate == false && signing_key&.certificate key = signing_key.certificate.public_key.to_s end if signing_key signing_cert = signing_key.certificate if allow_expired_certificate verification_time = signing_cert.not_after - 1 end # we explicitly trust the signing certificate, but it's not self-signed; # xmlsec is weird and decides not to trust it in that case, so we skip # certificate verification by xmlsec, and do it ourselves if certs.include?(signing_cert) && signing_cert.issuer != signing_cert.subject verification_time ||= Time.now.utc return ["certificate has expired"] if verification_time > signing_cert.not_after return ["certificate is not yet valid"] if verification_time < signing_cert.not_before verify_certificate = false end end certs = nil if key # we're using a key explicitly, ignoring the certs begin result = signature.verify_with(key: key, certs: certs, verification_time: verification_time, verify_certificates: verify_certificate) result ? [] : ["signature is invalid"] rescue XMLSec::VerificationError => e [e.] end end |