Commit 176a0f9

mo <mo@mokhan.ca>
2017-11-05 19:57:20
validate session time.
1 parent b99c010
Changed files (2)
lib
saml
spec
lib/saml/kit/response.rb
@@ -15,6 +15,7 @@ module Saml
       validate :must_be_valid_version
       validate :must_be_successful
       validate :must_match_request_id
+      validate :must_be_active_session
 
       def initialize(xml, request_id: nil)
         @content = xml
@@ -78,6 +79,22 @@ module Saml
         Fingerprint.new(certificate)
       end
 
+      def started_at
+        parse_date(@xml_hash.dig(name, 'Assertion', 'Conditions', 'NotBefore'))
+      end
+
+      def expired_at
+        parse_date(@xml_hash.dig(name, 'Assertion', 'Conditions', 'NotOnOrAfter'))
+      end
+
+      def expired?
+        Time.current > expired_at
+      end
+
+      def active?
+        Time.current > started_at && !expired?
+      end
+
       def self.parse(saml_response)
         new(Base64.decode64(saml_response))
       end
@@ -138,11 +155,22 @@ module Saml
         end
       end
 
+      def must_be_active_session
+        return unless login_response?
+        errors[:base] << error_message(:expired) unless active?
+      end
+
       def login_response?
         return false if to_xml.blank?
         @xml_hash[name].present?
       end
 
+      def parse_date(value)
+        DateTime.parse(value)
+      rescue
+        Time.at(0).to_datetime
+      end
+
       class Builder
         attr_reader :user, :request
         attr_accessor :id, :reference_id, :now, :name_id_format
spec/saml/response_spec.rb
@@ -221,5 +221,23 @@ RSpec.describe Saml::Kit::Response do
       allow(metadata).to receive(:matches?).and_return(true)
       expect(described_class.new(builder.to_xml, request_id: SecureRandom.uuid)).to_not be_valid
     end
+
+    it 'is invalid after a valid session window' do
+      allow(registry).to receive(:metadata_for).and_return(metadata)
+      allow(metadata).to receive(:matches?).and_return(true)
+
+      subject = described_class.new(builder.to_xml)
+      travel_to Saml::Kit.configuration.session_timeout.from_now + 5.seconds
+      expect(subject).to_not be_valid
+    end
+
+    it 'is invalid before the valid session window' do
+      allow(registry).to receive(:metadata_for).and_return(metadata)
+      allow(metadata).to receive(:matches?).and_return(true)
+
+      subject = described_class.new(builder.to_xml)
+      travel_to 5.seconds.ago
+      expect(subject).to_not be_valid
+    end
   end
 end