Commit 9b91421

mo <mo@mokhan.ca>
2017-11-15 18:17:26
serialize based on rules of HTTP-Redirect binding
1 parent b4a08db
lib/saml/kit/authentication_request.rb
@@ -20,6 +20,10 @@ module Saml
         @hash = Hash.from_xml(@content)
       end
 
+      def query_string_parameter
+        'SAMLRequest'
+      end
+
       def id
         to_h[name]['ID']
       end
@@ -29,7 +33,11 @@ module Saml
       end
 
       def acs_url
-        to_h[name]['AssertionConsumerServiceURL'] || registered_acs_url
+        #if signed? && trusted?
+          to_h[name]['AssertionConsumerServiceURL'] || registered_acs_url
+        #else
+          #registered_acs_url
+        #end
       end
 
       def issuer
lib/saml/kit/logout_request.rb
@@ -19,6 +19,10 @@ module Saml
         @xml_hash = Hash.from_xml(xml)
       end
 
+      def query_string_parameter
+        'SAMLRequest'
+      end
+
       def id
         to_h[name]['ID']
       end
lib/saml/kit/logout_response.rb
@@ -1,4 +1,3 @@
-
 module Saml
   module Kit
     class LogoutResponse
@@ -10,6 +9,10 @@ module Saml
         @xml_hash = Hash.from_xml(xml)
       end
 
+      def query_string_parameter
+        'SAMLResponse'
+      end
+
       def id
         to_h[name]['ID']
       end
lib/saml/kit/response.rb
@@ -26,6 +26,10 @@ module Saml
         @request_id = request_id
       end
 
+      def query_string_parameter
+        'SAMLResponse'
+      end
+
       def id
         to_h.fetch(name, {}).fetch('ID', nil)
       end
lib/saml/kit/url_builder.rb
@@ -1,16 +1,16 @@
 module Saml
   module Kit
     class UrlBuilder
-      def build(request, binding:, relay_state: nil)
+      def build(saml_document, binding:, relay_state: nil)
         payload = {
-          'SAMLRequest' => Content.encode_raw_saml(request.to_xml),
+          saml_document.query_string_parameter => Content.encode_raw_saml(saml_document.to_xml),
           'RelayState' => relay_state,
           'SigAlg' => Saml::Kit::Namespaces::SHA256,
         }.map do |(x, y)|
           "#{x}=#{y}"
         end.join('&')
         payload = URI.encode(payload)
-        "#{request.destination}?#{payload}&Signature=#{signature_for(payload)}"
+        "#{saml_document.destination}?#{payload}&Signature=#{signature_for(payload)}"
       end
 
       private
spec/saml/url_builder_spec.rb
@@ -5,16 +5,18 @@ RSpec.describe Saml::Kit::UrlBuilder do
     let(:xml) { "<xml></xml>" }
     let(:destination) { FFaker::Internet.http_url }
     let(:relay_state) { FFaker::Movie.title }
-    let(:query_params) { Hash[result_uri.query.split("&").map { |x| x.split('=', 2) }] }
-    let(:result) { subject.build(request, binding: :http_redirect, relay_state: relay_state) }
-    let(:result_uri) { URI.parse(result) }
 
     [
-      Saml::Kit::AuthenticationRequest,
-      Saml::Kit::LogoutRequest,
-    ].each do |request_type|
-      describe "AuthnRequest" do
-        let(:request) { instance_double(request_type, destination: destination, to_xml: xml) }
+      [Saml::Kit::AuthenticationRequest, 'SAMLRequest'],
+      [Saml::Kit::LogoutRequest, 'SAMLRequest'],
+      [Saml::Kit::Response, 'SAMLResponse'],
+      [Saml::Kit::LogoutResponse, 'SAMLResponse'],
+    ].each do |(response_type, query_string_parameter)|
+      describe response_type.to_s do
+        let(:response) { instance_double(response_type, destination: destination, to_xml: xml, query_string_parameter: query_string_parameter) }
+        let(:result) { subject.build(response, binding: :http_redirect, relay_state: relay_state) }
+        let(:result_uri) { URI.parse(result) }
+        let(:query_params) { Hash[result_uri.query.split("&").map { |x| x.split('=', 2) }] }
 
         it 'returns a url containing the target location' do
           expect(result_uri.scheme).to eql("http")
@@ -24,8 +26,8 @@ RSpec.describe Saml::Kit::UrlBuilder do
         it 'includes the message deflated (without header and checksum), base64-encoded, and URL-encoded' do
           level = Zlib::BEST_COMPRESSION
           expected = URI.encode(Base64.encode64(Zlib::Deflate.deflate(xml, level)[2..-5]).gsub(/\n/, ''))
-          expect(result).to include("SAMLRequest=#{expected}")
-          expect(query_params['SAMLRequest']).to eql(expected)
+          expect(result).to include("#{query_string_parameter}=#{expected}")
+          expect(query_params[query_string_parameter]).to eql(expected)
         end
 
         it 'includes the relay state' do
@@ -33,11 +35,10 @@ RSpec.describe Saml::Kit::UrlBuilder do
           expect(result).to include("RelayState=#{URI.encode(relay_state)}")
         end
 
-        # https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf section 3.4.4.1
         it 'includes a signature' do
           expect(query_params['SigAlg']).to eql(URI.encode(Saml::Kit::Namespaces::SHA256))
 
-          payload = "SAMLRequest=#{query_params['SAMLRequest']}"
+          payload = "#{query_string_parameter}=#{query_params[query_string_parameter]}"
           payload << "&RelayState=#{query_params['RelayState']}"
           payload << "&SigAlg=#{query_params['SigAlg']}"
           expected_signature = Base64.strict_encode64(Saml::Kit.configuration.signing_private_key.sign(OpenSSL::Digest::SHA256.new, payload))