Commit 899fba9

mo <mo.khan@gmail.com>
2017-11-04 19:23:15
validate authnrequest against the xsd.
1 parent 66aa31b
lib/saml/kit/authentication_request.rb
@@ -1,12 +1,15 @@
 module Saml
   module Kit
     class AuthenticationRequest
+      PROTOCOL_XSD = File.expand_path("./xsd/saml-schema-protocol-2.0.xsd", File.dirname(__FILE__)).freeze
+
       include ActiveModel::Validations
       validates_presence_of :content
       validates_presence_of :acs_url, if: :login_request?
       validate :must_be_request
       validate :must_have_valid_signature
       validate :must_be_registered_service_provider
+      validate :must_match_xsd
 
       attr_reader :content, :name
 
@@ -82,6 +85,16 @@ module Saml
         errors[:base] << error_message(:invalid) unless login_request?
       end
 
+      def must_match_xsd
+        Dir.chdir(File.dirname(PROTOCOL_XSD)) do
+          xsd = Nokogiri::XML::Schema(IO.read(PROTOCOL_XSD))
+          document = Nokogiri::XML(to_xml)
+          xsd.validate(document).each do |error|
+            errors[:base] << error.message
+          end
+        end
+      end
+
       def login_request?
         return false if to_xml.blank?
         @hash[name].present?
@@ -103,8 +116,8 @@ module Saml
         def to_xml(xml = ::Builder::XmlMarkup.new)
           signature = Signature.new(id)
           xml.tag!('samlp:AuthnRequest', request_options) do
-            signature.template(xml)
             xml.tag!('saml:Issuer', issuer)
+            signature.template(xml)
             xml.tag!('samlp:NameIDPolicy', Format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")
           end
           signature.finalize(xml)
spec/saml/authentication_request_spec.rb
@@ -53,7 +53,8 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
     end
 
     it 'is valid when left untampered' do
-      expect(described_class.new(raw_xml)).to be_valid
+      subject = described_class.new(raw_xml)
+      expect(subject).to be_valid
     end
 
     it 'is invalid if the document has been tampered with' do
@@ -107,6 +108,24 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
 
       expect(described_class.new(xml)).to be_valid
     end
+
+    it 'validates the schema of the request' do
+      xml = ::Builder::XmlMarkup.new
+      id = SecureRandom.uuid
+      options = {
+        "xmlns:samlp" => Saml::Kit::Namespaces::PROTOCOL,
+        AssertionConsumerServiceURL: acs_url,
+        ID: "_#{id}",
+      }
+      signature = Saml::Kit::Signature.new(id)
+      xml.tag!('samlp:AuthnRequest', options) do
+        signature.template(xml)
+        xml.Fake do
+          xml.NotAllowed "Huh?"
+        end
+      end
+      expect(described_class.new(signature.finalize(xml))).to be_invalid
+    end
   end
 
   describe "#acs_url" do
spec/saml/default_registry_spec.rb
@@ -44,4 +44,6 @@ RSpec.describe Saml::Kit::DefaultRegistry do
       expect(result).to be_instance_of(Saml::Kit::IdentityProviderMetadata)
     end
   end
+
+  xit 'registers metadata that serves as both an IDP and SP'
 end