Commit 172a4ac

mo <mo.khan@gmail.com>
2018-02-15 20:03:58
reproduce defect where signature is not parsed from encrypted assertion.
1 parent 1e833ba
lib/saml/kit/builders/response.rb
@@ -20,6 +20,7 @@ module Saml
           @version = "2.0"
           @status_code = Namespaces::SUCCESS
           @issuer = configuration.entity_id
+          @encryption_certificate = request.try(:provider).try(:encryption_certificates).try(:last)
           @encrypt = encryption_certificate.present?
           @configuration = configuration
         end
@@ -28,13 +29,6 @@ module Saml
           Saml::Kit::Response.new(to_xml, request_id: request.id, configuration: configuration)
         end
 
-        def encryption_certificate
-          request.provider.encryption_certificates.first
-        rescue => error
-          Saml::Kit.logger.error(error)
-          nil
-        end
-
         def assertion
           @assertion ||=
             begin
lib/saml/kit/assertion.rb
@@ -9,12 +9,13 @@ module Saml
       attr_reader :name
       attr_accessor :occurred_at
 
-      def initialize(node, configuration: Saml::Kit.configuration)
+      def initialize(node, configuration: Saml::Kit.configuration, private_keys: [])
         @name = "Assertion"
         @node = node
         @xml_hash = hash_from(node)['Response'] || {}
         @configuration = configuration
         @occurred_at = Time.current
+        @private_keys = configuration.private_keys(use: :encryption) + private_keys
       end
 
       def issuer
@@ -79,14 +80,18 @@ module Saml
         assertion.present?
       end
 
+      def to_xml(pretty: false)
+        pretty ? @node.to_xml(indent: 2) : @node.to_s
+      end
+
       private
 
       attr_reader :configuration
+      attr_reader :private_keys
 
       def assertion
         @assertion ||=
           if encrypted?
-            private_keys = configuration.private_keys(use: :encryption)
             decryptor = ::Xml::Kit::Decryption.new(private_keys: private_keys)
             decrypted = decryptor.decrypt_hash(@xml_hash['EncryptedAssertion'])
             Saml::Kit.logger.debug(decrypted)
lib/saml/kit/configuration.rb
@@ -85,7 +85,7 @@ module Saml
       # Return each private for a specific use.
       #
       # @param use [Symbol] the type of key pair to return `nil`, `:signing` or `:encryption`
-      def private_keys(use: :signing)
+      def private_keys(use: nil)
         key_pairs(use: use).flat_map(&:private_key)
       end
 
lib/saml/kit/response.rb
@@ -15,16 +15,14 @@ module Saml
         super(xml, name: "Response", configuration: configuration)
       end
 
-      def assertion
-        @assertion ||= 
+      def assertion(private_keys = configuration.private_keys(use: :encryption))
+        @assertion ||=
           begin
-            node = at_xpath(
-              [
-                '/samlp:Response/saml:Assertion',
-                '/samlp:Response/saml:EncryptedAssertion'
-              ].join('|')
-            )
-            Saml::Kit::Assertion.new(node, configuration: @configuration)
+            node = at_xpath([
+              '/samlp:Response/saml:Assertion',
+              '/samlp:Response/saml:EncryptedAssertion'
+            ].join('|'))
+            Saml::Kit::Assertion.new(node, configuration: @configuration, private_keys: private_keys)
           end
       end
 
lib/saml/kit/xml_templatable.rb
@@ -16,6 +16,11 @@ module Saml
           (embed_signature && @signing_key_pair.present?)
       end
 
+      def encrypt_with(key_pair)
+        self.encrypt = true
+        self.encryption_certificate = key_pair.certificate
+      end
+
       def digest_method
         configuration.digest_method
       end
spec/saml/assertion_spec.rb
@@ -111,4 +111,19 @@ XML
       expect(subject).to be_present
     end
   end
+
+  describe "#signed?" do
+    let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: ::Xml::Kit::Id.generate, issuer: FFaker::Internet.http_url, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
+    let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: { id: SecureRandom.uuid }) }
+
+    it 'detects a signature in an encrypted assertion' do
+      encryption_key_pair = Xml::Kit::KeyPair.generate(use: :encryption)
+      response = Saml::Kit::Response.build(user, request) do |x|
+        x.sign_with(Xml::Kit::KeyPair.generate(use: :signing))
+        x.encrypt_with(encryption_key_pair)
+      end
+      subject = response.assertion([encryption_key_pair.private_key])
+      expect(subject).to be_signed
+    end
+  end
 end