Class: WSDL::Security::Signature
- Inherits:
-
Object
- Object
- WSDL::Security::Signature
- Defined in:
- lib/wsdl/security/signature.rb
Overview
Handles XML Digital Signature (XML-DSig) creation for WS-Security.
The Signature class orchestrates the signing process for SOAP messages:
- Digests referenced elements (Timestamp, Body, etc.)
- Builds the SignedInfo element with References
- Canonicalizes and signs the SignedInfo
- Builds the complete Signature element with KeyInfo
Constant Summary collapse
- SigAlg =
Local aliases for constants
Constants::Algorithms::Signature
- SecurityNS =
Alias for WS-Security namespace constants.
Constants::NS::Security
- SignatureNS =
Alias for XML Signature namespace constants.
Constants::NS::Signature
- X509 =
Alias for X.509 token profile constants.
Constants::TokenProfiles::X509
- Encoding =
Alias for XML encoding URI constants.
Constants::Encoding
- KeyRef =
Alias for supported key reference strategies.
Constants::KeyReference
- SIGNATURE_ALGORITHMS =
Signature algorithm configurations
{ sha1: { id: SigAlg::RSA_SHA1, digest: 'SHA1' }, sha256: { id: SigAlg::RSA_SHA256, digest: 'SHA256' }, sha512: { id: SigAlg::RSA_SHA512, digest: 'SHA512' } }.freeze
- DEFAULT_ALGORITHM =
Default digest algorithm
:sha256- DEFAULT_KEY_REFERENCE =
Default key reference method
Constants::KeyReference::BINARY_SECURITY_TOKEN
Instance Attribute Summary collapse
-
#certificate ⇒ OpenSSL::X509::Certificate
readonly
Returns the X.509 certificate.
-
#digest_algorithm ⇒ Symbol
readonly
Returns the digest algorithm symbol.
-
#explicit_namespace_prefixes ⇒ Boolean
readonly
Returns whether explicit namespace prefixes are enabled.
-
#key_reference ⇒ Symbol
readonly
Returns the key reference method.
-
#private_key ⇒ OpenSSL::PKey::RSA, OpenSSL::PKey::EC
readonly
Returns the private key.
-
#references ⇒ Array<Reference>
readonly
Returns the references to be signed.
-
#security_token_id ⇒ String
readonly
Returns the unique ID for the BinarySecurityToken.
Instance Method Summary collapse
-
#apply(document, security_node) ⇒ Nokogiri::XML::Document
Applies the signature to the document.
-
#clear_references ⇒ self
Clears all references to allow reuse.
-
#encoded_certificate ⇒ String
Returns the Base64-encoded DER representation of the certificate.
-
#explicit_namespace_prefixes? ⇒ Boolean
Returns whether explicit namespace prefixes should be used.
-
#initialize(certificate:, private_key:, digest_algorithm: DEFAULT_ALGORITHM, security_token_id: nil, key_reference: DEFAULT_KEY_REFERENCE, explicit_namespace_prefixes: false) ⇒ Signature
constructor
Creates a new Signature instance.
-
#inspect ⇒ String
Returns a safe string representation that hides the private key.
-
#references? ⇒ Boolean
Returns whether any references have been added.
-
#sign_element(node, id: nil, inclusive_namespaces: nil) ⇒ self
(also: #digest!)
Adds an element to the list of elements to be signed.
Constructor Details
#initialize(certificate:, private_key:, digest_algorithm: DEFAULT_ALGORITHM, security_token_id: nil, key_reference: DEFAULT_KEY_REFERENCE, explicit_namespace_prefixes: false) ⇒ Signature
Creates a new Signature instance.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/wsdl/security/signature.rb', line 135 def initialize(certificate:, private_key:, digest_algorithm: DEFAULT_ALGORITHM, security_token_id: nil, key_reference: DEFAULT_KEY_REFERENCE, explicit_namespace_prefixes: false) @certificate = certificate or raise ArgumentError, 'certificate is required' @private_key = private_key or raise ArgumentError, 'private_key is required' @digest_algorithm = digest_algorithm @security_token_id = security_token_id || IdGenerator.for('SecurityToken') @key_reference = key_reference @explicit_namespace_prefixes = explicit_namespace_prefixes @references = [] @canonicalizer = Canonicalizer.new(algorithm: :exclusive_1_0) @digester = Digester.new(algorithm: digest_algorithm) @xml_helper = XmlBuilderHelper.new(explicit_prefixes: explicit_namespace_prefixes) @signature_algorithm = SIGNATURE_ALGORITHMS[digest_algorithm] or raise ArgumentError, "Unknown digest algorithm: #{digest_algorithm.inspect}" end |
Instance Attribute Details
#certificate ⇒ OpenSSL::X509::Certificate (readonly)
Returns the X.509 certificate.
95 96 97 |
# File 'lib/wsdl/security/signature.rb', line 95 def certificate @certificate end |
#digest_algorithm ⇒ Symbol (readonly)
Returns the digest algorithm symbol.
103 104 105 |
# File 'lib/wsdl/security/signature.rb', line 103 def digest_algorithm @digest_algorithm end |
#explicit_namespace_prefixes ⇒ Boolean (readonly)
Returns whether explicit namespace prefixes are enabled.
119 120 121 |
# File 'lib/wsdl/security/signature.rb', line 119 def explicit_namespace_prefixes @explicit_namespace_prefixes end |
#key_reference ⇒ Symbol (readonly)
Returns the key reference method.
115 116 117 |
# File 'lib/wsdl/security/signature.rb', line 115 def key_reference @key_reference end |
#private_key ⇒ OpenSSL::PKey::RSA, OpenSSL::PKey::EC (readonly)
Returns the private key.
99 100 101 |
# File 'lib/wsdl/security/signature.rb', line 99 def private_key @private_key end |
#references ⇒ Array<Reference> (readonly)
Returns the references to be signed.
111 112 113 |
# File 'lib/wsdl/security/signature.rb', line 111 def references @references end |
#security_token_id ⇒ String (readonly)
Returns the unique ID for the BinarySecurityToken.
107 108 109 |
# File 'lib/wsdl/security/signature.rb', line 107 def security_token_id @security_token_id end |
Instance Method Details
#apply(document, security_node) ⇒ Nokogiri::XML::Document
Applies the signature to the document.
This method builds the complete Signature element including:
- BinarySecurityToken (X.509 certificate) - if using :binary_security_token
- SignedInfo with References
- SignatureValue
- KeyInfo with appropriate reference type
206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/wsdl/security/signature.rb', line 206 def apply(document, security_node) # Build SignedInfo signed_info_xml = build_signed_info # Canonicalize SignedInfo and compute signature canonical_signed_info = @canonicalizer.canonicalize(signed_info_xml) signature_value = compute_signature(canonical_signed_info) # Build and insert complete Signature element build_signature_element(document, security_node, signed_info_xml, signature_value) document end |
#clear_references ⇒ self
Clears all references to allow reuse.
250 251 252 253 |
# File 'lib/wsdl/security/signature.rb', line 250 def clear_references @references = [] self end |
#encoded_certificate ⇒ String
Returns the Base64-encoded DER representation of the certificate.
This is used in the BinarySecurityToken element.
226 227 228 |
# File 'lib/wsdl/security/signature.rb', line 226 def encoded_certificate Base64.strict_encode64(@certificate.to_der) end |
#explicit_namespace_prefixes? ⇒ Boolean
Returns whether explicit namespace prefixes should be used.
242 243 244 |
# File 'lib/wsdl/security/signature.rb', line 242 def explicit_namespace_prefixes? @explicit_namespace_prefixes == true end |
#inspect ⇒ String
Returns a safe string representation that hides the private key.
This method ensures that private keys are never accidentally exposed in logs, error messages, debugger output, or stack traces.
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/wsdl/security/signature.rb', line 267 def inspect cert_subject = begin @certificate.subject.to_s rescue StandardError 'unknown' end parts = [ "algorithm=#{@digest_algorithm.inspect}", "key_reference=#{@key_reference.inspect}", 'private_key=[REDACTED]', "certificate=#{cert_subject.inspect}", "references=#{@references.size}" ] "#<#{self.class.name} #{parts.join(' ')}>" end |
#references? ⇒ Boolean
Returns whether any references have been added.
234 235 236 |
# File 'lib/wsdl/security/signature.rb', line 234 def references? !@references.empty? end |
#sign_element(node, id: nil, inclusive_namespaces: nil) ⇒ self Also known as: digest!
Adds an element to the list of elements to be signed.
The element must have a wsu:Id attribute that will be used as the Reference URI. If the element doesn't have an ID, you must provide one.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/wsdl/security/signature.rb', line 166 def sign_element(node, id: nil, inclusive_namespaces: nil) element_id = id || extract_id(node) raise ArgumentError, 'Element must have a wsu:Id attribute or id must be provided' unless element_id # Canonicalize and compute digest canonical_xml = @canonicalizer.canonicalize(node, inclusive_namespaces: inclusive_namespaces) digest_value = @digester.base64_digest(canonical_xml) @references << Reference.new( id: element_id, digest_value: digest_value, inclusive_namespaces: inclusive_namespaces ) self end |