Commit 56d8f0f

mo <mo@mokhan.ca>
2018-09-17 20:45:25
make assertion inherit from document.
1 parent 67c41f9
lib/saml/kit/concerns/xsd_validatable.rb
@@ -19,7 +19,7 @@ module Saml
 
         Dir.chdir(File.dirname(xsd)) do
           xsd = Nokogiri::XML::Schema(IO.read(xsd))
-          xsd.validate(to_nokogiri).each do |error|
+          xsd.validate(to_nokogiri.document).each do |error|
             errors[:base] << error.message
           end
         end
lib/saml/kit/locales/en.yml
@@ -5,8 +5,12 @@ en:
       Assertion:
         cannot_decrypt: "cannot be decrypted."
         expired: "must not be expired."
-        must_match_issuer: "must match entityId."
+        invalid: "must contain Assertion."
+        invalid_fingerprint: "is not registered."
+        invalid_version: "must be 2.0."
         must_contain_single_assertion: "must contain single Assertion."
+        must_match_issuer: "must match entityId."
+        unregistered: "is unregistered."
       AuthnRequest:
         invalid: "must contain AuthnRequest."
         invalid_fingerprint: "is not registered."
lib/saml/kit/assertion.rb
@@ -5,11 +5,7 @@ module Saml
     # This class validates the Assertion
     # element nested in a Response element
     # of a SAML document.
-    class Assertion
-      include ActiveModel::Validations
-      include Buildable
-      include Translatable
-      include XmlParseable
+    class Assertion < Document
       extend Forwardable
       XPATH = [
         '/samlp:Response/saml:Assertion',
@@ -36,12 +32,21 @@ module Saml
         @encrypted = false
         keys = configuration.private_keys(use: :encryption) + private_keys
         decrypt(::Xml::Kit::Decryption.new(private_keys: keys.uniq))
+        super(to_s, name: 'Assertion', configuration: configuration)
+      end
+
+      def id
+        at_xpath('./@ID').try(:value)
       end
 
       def issuer
         at_xpath('./saml:Issuer').try(:text)
       end
 
+      def version
+        at_xpath('./@Version').try(:value)
+      end
+
       def name_id
         at_xpath('./saml:Subject/saml:NameID').try(:text)
       end
@@ -67,6 +72,10 @@ module Saml
         now > drifted_started_at && !expired?(now)
       end
 
+      def expected_type?
+        at_xpath("//saml:Assertion|//saml:EncryptedAssertion").present?
+      end
+
       def attribute_statement
         @attribute_statement ||=
           AttributeStatement.new(search('./saml:AttributeStatement'))
@@ -89,12 +98,6 @@ module Saml
         @to_nokogiri.to_s
       end
 
-      class << self
-        def builder_class
-          Saml::Kit::Builders::Assertion
-        end
-      end
-
       private
 
       attr_reader :configuration
lib/saml/kit/document.rb
@@ -83,10 +83,11 @@ module Saml
         # @!visibility private
         def builder_class # :nodoc:
           {
-            Response.to_s => Saml::Kit::Builders::Response,
-            LogoutResponse.to_s => Saml::Kit::Builders::LogoutResponse,
+            Assertion.to_s => Saml::Kit::Builders::Assertion,
             AuthenticationRequest.to_s => Saml::Kit::Builders::AuthenticationRequest,
             LogoutRequest.to_s => Saml::Kit::Builders::LogoutRequest,
+            LogoutResponse.to_s => Saml::Kit::Builders::LogoutResponse,
+            Response.to_s => Saml::Kit::Builders::Response,
           }[name] || (raise ArgumentError, "Unknown SAML Document #{name}")
         end
       end
spec/saml/kit/builders/assertion_builder_spec.rb
@@ -10,13 +10,21 @@ RSpec.describe Saml::Kit::Builders::Assertion do
     let(:authn_request) { instance_double(Saml::Kit::AuthenticationRequest, id: Xml::Kit::Id.generate, assertion_consumer_service_url: assertion_consumer_service_url, issuer: issuer, name_id_format: Saml::Kit::Namespaces::EMAIL_ADDRESS, provider: provider, trusted?: true, signed?: true) }
     let(:provider) { instance_double(Saml::Kit::ServiceProviderMetadata, want_assertions_signed: false, encryption_certificates: [configuration.certificates(use: :encryption).last]) }
     let(:issuer) { FFaker::Internet.uri('https') }
+    let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
     let(:configuration) do
       Saml::Kit::Configuration.new do |config|
         config.entity_id = issuer
+        config.registry = registry
         config.generate_key_pair_for(use: :signing)
         config.generate_key_pair_for(use: :encryption)
       end
     end
+    let(:metadata) do
+      Saml::Kit::Metadata.build(configuration: configuration) do |x|
+        x.build_identity_provider
+      end
+    end
+    before { allow(registry).to receive(:metadata_for).and_return(metadata) }
 
     specify { expect(subject.build).to be_valid }
     specify { expect(subject.build.issuer).to eql(issuer) }
spec/saml/kit/assertion_spec.rb
@@ -243,12 +243,21 @@ RSpec.describe Saml::Kit::Assertion do
 
   describe '.new' do
     let(:user) { instance_double(User, name_id_for: SecureRandom.uuid, assertion_attributes_for: {}) }
-    let(:saml_request) { double(id: SecureRandom.uuid, issuer: configuration.entity_id) }
+    let(:saml_request) { double(id: Xml::Kit::Id.generate, issuer: configuration.entity_id) }
+    let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
     let(:configuration) do
       Saml::Kit::Configuration.new do |x|
         x.entity_id = FFaker::Internet.uri('https')
+        x.registry = registry
       end
     end
+    let(:metadata) do
+      Saml::Kit::Metadata.build(configuration: configuration) do |x|
+        x.build_identity_provider
+      end
+    end
+
+    before { allow(registry).to receive(:metadata_for).with(configuration.entity_id).and_return(metadata) }
 
     it 'parses a raw xml assertion' do
       saml = Saml::Kit::Response.build(user, saml_request, configuration: configuration)