lib/akami/wsse.rb in akami-1.0.0 vs lib/akami/wsse.rb in akami-1.1.0

- old
+ new

@@ -1,10 +1,16 @@ require "base64" require "digest/sha1" -require "akami/core_ext/time" +require "akami/core_ext/hash" +require "akami/xpath_helper" +require "akami/c14n_helper" +require "time" require "gyoku" +require "akami/wsse/verify_signature" +require "akami/wsse/signature" + module Akami # = Akami::WSSE # # Building Web Service Security. @@ -38,12 +44,20 @@ self.username = username self.password = password self.digest = digest end - attr_accessor :username, :password, :created_at, :expires_at + attr_accessor :username, :password, :created_at, :expires_at, :signature, :verify_response + def sign_with=(klass) + @signature = klass + end + + def signature? + !!@signature + end + # Returns whether to use WSSE digest. Defaults to +false+. def digest? !!@digest end @@ -62,13 +76,24 @@ # Sets whether to generate a wsu:Timestamp header. def timestamp=(timestamp) @wsu_timestamp = timestamp end + # Hook for Soap::XML that allows us to add attributes to the env:Body tag + def body_attributes + if signature? + signature.body_attributes + else + {} + end + end + # Returns the XML for a WSSE header. def to_xml - if username_token? && timestamp? + if signature? and signature.have_document? + Gyoku.xml wsse_signature.merge!(hash) + elsif username_token? && timestamp? Gyoku.xml wsse_username_token.merge!(wsu_timestamp) { |key, v1, v2| v1.merge!(v2) { |key, v1, v2| v1.merge!(v2) } } @@ -98,27 +123,49 @@ "wsse:Password" => password, :attributes! => { "wsse:Password" => { "Type" => PASSWORD_TEXT_URI } } end end + def wsse_signature + signature_hash = signature.to_token + + # First key/value is tag/hash + tag, hash = signature_hash.shift + + security_hash nil, tag, hash, signature_hash + end + # Returns a Hash containing wsu:Timestamp details. def wsu_timestamp security_hash :wsu, "Timestamp", - "wsu:Created" => (created_at || Time.now).xs_datetime, - "wsu:Expires" => (expires_at || (created_at || Time.now) + 60).xs_datetime + "wsu:Created" => (created_at || Time.now).utc.xmlschema, + "wsu:Expires" => (expires_at || (created_at || Time.now) + 60).utc.xmlschema end # Returns a Hash containing wsse/wsu Security details for a given # +namespace+, +tag+ and +hash+. - def security_hash(namespace, tag, hash) - { + def security_hash(namespace, tag, hash, extra_info = {}) + key = [namespace, tag].compact.join(":") + + sec_hash = { "wsse:Security" => { - "#{namespace}:#{tag}" => hash, - :attributes! => { "#{namespace}:#{tag}" => { "wsu:Id" => "#{tag}-#{count}", "xmlns:wsu" => WSU_NAMESPACE } } + key => hash }, :attributes! => { "wsse:Security" => { "xmlns:wsse" => WSE_NAMESPACE } } } + + unless extra_info.empty? + sec_hash["wsse:Security"].merge!(extra_info) + end + + if signature? + sec_hash[:attributes!].merge!("soapenv:mustUnderstand" => "1") + else + sec_hash["wsse:Security"].merge!(:attributes! => { key => { "wsu:Id" => "#{tag}-#{count}", "xmlns:wsu" => WSU_NAMESPACE } }) + end + + sec_hash end # Returns the WSSE password, encrypted for digest authentication. def digest_password token = nonce + timestamp + password @@ -135,10 +182,10 @@ (0...100).map { ("a".."z").to_a[rand(26)] }.join end # Returns a WSSE timestamp. def timestamp - @timestamp ||= Time.now.xs_datetime + @timestamp ||= Time.now.xmlschema end # Returns a new number with every call. def count @count ||= 0