Comparing changes

v1.0.9 v1.0.10
38 commits 97 files changed

Commits

4299408 bump version. mo 2018-02-26 03:39:54
0fc0290 frozen_string_literal. mo 2018-02-26 03:35:38
33d4523 reuse namespaces in matcher. mo 2018-02-26 03:32:47
a4df521 symbolize. mo 2018-02-26 03:24:24
47a51c3 fix broken tests. mo 2018-02-26 03:22:56
46b0d25 fix rubocop warnings. mo 2018-02-26 03:12:55
f7cd8c5 use xpath to parse metadata. mo 2018-02-26 03:08:04
25dc015 parse expected type with xpath. mo 2018-02-26 02:57:46
a9463f1 parse nameid using xpath. mo 2018-02-26 02:53:19
9d41e9d rename to name_id_policy. mo 2018-02-26 02:46:48
46e4775 remove deprecation warning. mo 2018-02-26 02:46:03
c6b0921 parse ACS using xpath. mo 2018-02-26 02:36:49
9cc1812 parse InResponseTo with xpath. mo 2018-02-26 02:34:44
d3ce092 parse status code using xpath. mo 2018-02-26 02:32:47
7deba5b delegate to to_nokogiri. mo 2018-02-26 02:15:23
0e371fc remove unused method. mo 2018-02-26 02:12:17
b98e775 use nokogiri. mo 2018-02-26 02:09:59
bdc4a9e start from current node. mo 2018-02-26 01:53:35
d73a510 fix rubocop errors. mo 2018-02-26 01:20:15
cd5f7e2 add ==> mo 2018-02-26 01:12:51
e068118 merge status and timestamps. mo 2018-02-26 01:09:22
4343d46 xpath to parse document ID mo 2018-02-26 01:05:54
753276b remove xml_hash from assertion. mo 2018-02-26 00:47:00
cfb4f6d remove unused assertion method. mo 2018-02-26 00:40:15
98defed use xpath to find audiences. mo 2018-02-26 00:35:20
970619f use xpath to parse attributes. mo 2018-02-26 00:28:55
b952585 parse dates via xpath. mo 2018-02-26 00:18:29
72c860b use xpath to find nameid. mo 2018-02-25 23:57:30
5195eb2 use xpath to find issuer. mo 2018-02-25 23:55:30
14fad30 remove time command. mo 2018-02-18 22:46:45
Changed files (97)
bin
exe
lib
spec
bin/cibuild
@@ -7,8 +7,7 @@ set -e
 
 cd "$(dirname "$0")/.."
 
-echo "Started at…"
-date "+%H:%M:%S"
+echo [$(date "+%H:%M:%S")] "==> Started at…"
 
 # GC customizations
 export RUBY_GC_MALLOC_LIMIT=79000000
@@ -19,4 +18,4 @@ export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
 
 ruby -v
 gem install bundler --no-ri --no-rdoc --conservative
-time bin/test
+bin/test
bin/console
@@ -1,4 +1,5 @@
 #!/usr/bin/env ruby
+# frozen_string_literal: true
 
 require 'bundler/setup'
 require 'saml/kit'
bin/lint
@@ -4,10 +4,8 @@ set -e
 
 [ -z "$DEBUG" ] || set -x
 
-echo "==> Running setup…"
-date "+%H:%M:%S"
+echo [$(date "+%H:%M:%S")] "==> Running setup…"
 bin/setup
 
-echo "==> Running linters…"
-date "+%H:%M:%S"
+echo [$(date "+%H:%M:%S")] "==> Running linters…"
 bundle exec rake rubocop
bin/setup
@@ -4,5 +4,3 @@ IFS=$'\n\t'
 set -vx
 
 bundle check || bundle install --jobs $(nproc)
-
-# Do any other automated setup that you need to do here
bin/test
@@ -10,10 +10,8 @@ cd "$(dirname "$0")/.."
 
 [ -z "$DEBUG" ] || set -x
 
-echo "==> Running setup…"
-date "+%H:%M:%S"
+echo [$(date "+%H:%M:%S")] "==> Running setup…"
 bin/setup
 
-echo "==> Running tests…"
-date "+%H:%M:%S"
+echo [$(date "+%H:%M:%S")] "==> Running tests…"
 bundle exec rake spec
exe/saml-kit-create-self-signed-certificate
@@ -1,4 +1,6 @@
 #!/usr/bin/env ruby
+# frozen_string_literal: true
+
 require 'saml/kit'
 
 Saml::Kit.deprecate("Use the 'saml-kit-cli' gem instead. saml-kit-create-self-signed-certificate")
exe/saml-kit-decode-http-post
@@ -1,4 +1,6 @@
 #!/usr/bin/env ruby
+# frozen_string_literal: true
+
 require 'saml/kit'
 
 Saml::Kit.deprecate("Use the 'saml-kit-cli' gem instead. saml-kit-decode-http-post")
exe/saml-kit-decode-http-redirect
@@ -1,4 +1,6 @@
 #!/usr/bin/env ruby
+# frozen_string_literal: true
+
 require 'saml/kit'
 
 Saml::Kit.deprecate("Use the 'saml-kit-cli' gem instead. saml-kit-decode-http-redirect*")
lib/saml/kit/bindings/binding.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Bindings
lib/saml/kit/bindings/http_post.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Bindings
lib/saml/kit/bindings/http_redirect.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Bindings
lib/saml/kit/bindings/url_builder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Bindings
lib/saml/kit/builders/templates/assertion.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.Assertion(assertion_options) do
   xml.Issuer issuer
   signature_for(reference_id: reference_id, xml: xml)
lib/saml/kit/builders/templates/authentication_request.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.instruct!
 xml.tag!('samlp:AuthnRequest', request_options) do
   xml.tag!('saml:Issuer', issuer)
lib/saml/kit/builders/templates/encrypted_assertion.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.EncryptedAssertion xmlns: Saml::Kit::Namespaces::ASSERTION do
   encryption_for(xml: xml) do |xml|
     render assertion, xml: xml
lib/saml/kit/builders/templates/identity_provider_metadata.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.IDPSSODescriptor descriptor_options do
   configuration.certificates(use: :signing).each do |certificate|
     render certificate, xml: xml
lib/saml/kit/builders/templates/logout_request.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.instruct!
 xml.LogoutRequest logout_request_options do
   xml.Issuer({ xmlns: Saml::Kit::Namespaces::ASSERTION }, issuer)
lib/saml/kit/builders/templates/logout_response.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.instruct!
 xml.LogoutResponse logout_response_options do
   xml.Issuer(issuer, xmlns: Saml::Kit::Namespaces::ASSERTION)
lib/saml/kit/builders/templates/metadata.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.instruct!
 xml.EntityDescriptor entity_descriptor_options do
   signature_for(reference_id: id, xml: xml)
lib/saml/kit/builders/templates/response.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.instruct!
 xml.Response response_options do
   xml.Issuer(issuer, xmlns: Saml::Kit::Namespaces::ASSERTION)
lib/saml/kit/builders/templates/service_provider_metadata.builder
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 xml.SPSSODescriptor descriptor_options do
   configuration.certificates(use: :signing).each do |certificate|
     render certificate, xml: xml
lib/saml/kit/builders/assertion.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/authentication_request.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/encrypted_assertion.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/identity_provider_metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/logout_request.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/logout_response.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/response.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/builders/service_provider_metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Builders
lib/saml/kit/rspec/have_query_param.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'uri'
 
 RSpec::Matchers.define :have_query_param do |key|
lib/saml/kit/rspec/have_xpath.rb
@@ -1,13 +1,8 @@
+# frozen_string_literal: true
+
 RSpec::Matchers.define :have_xpath do |xpath|
   match do |actual|
-    namespaces = {
-      "NameFormat": Saml::Kit::Namespaces::ATTR_SPLAT,
-      "ds": ::Xml::Kit::Namespaces::XMLDSIG,
-      "md": Saml::Kit::Namespaces::METADATA,
-      "saml": Saml::Kit::Namespaces::ASSERTION,
-      "samlp": Saml::Kit::Namespaces::PROTOCOL,
-    }
-    xml_document(actual).xpath(xpath, namespaces).any?
+    xml_document(actual).xpath(xpath, Saml::Kit::Document::NAMESPACES).any?
   end
 
   failure_message do |actual|
lib/saml/kit/assertion.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     class Assertion
@@ -18,22 +20,18 @@ module Saml
       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
-        decrypt!(::Xml::Kit::Decryption.new(
-                   private_keys: (
-                     configuration.private_keys(use: :encryption) + private_keys
-                   ).uniq
-        ))
+        private_keys = (configuration.private_keys(use: :encryption) + private_keys).uniq
+        decrypt!(::Xml::Kit::Decryption.new(private_keys: private_keys))
       end
 
       def issuer
-        assertion.fetch('Issuer')
+        at_xpath('./saml:Issuer').try(:text)
       end
 
       def name_id
-        assertion.fetch('Subject', {}).fetch('NameID', nil)
+        at_xpath('./saml:Subject/saml:NameID').try(:text)
       end
 
       def signed?
@@ -54,35 +52,26 @@ module Saml
       end
 
       def attributes
-        @attributes ||=
-          begin
-            attrs = assertion.fetch('AttributeStatement', {}).fetch('Attribute', [])
-            items = if attrs.is_a? Hash
-                      [[attrs['Name'], attrs['AttributeValue']]]
-                    else
-                      attrs.map { |item| [item['Name'], item['AttributeValue']] }
-                    end
-            Hash[items].with_indifferent_access
-          end
+        @attributes ||= search('./saml:AttributeStatement/saml:Attribute').inject({}) do |memo, item|
+          memo[item.attribute('Name').value] = item.at_xpath('./saml:AttributeValue', Saml::Kit::Document::NAMESPACES).try(:text)
+          memo
+        end.with_indifferent_access
       end
 
       def started_at
-        parse_date(assertion.fetch('Conditions', {}).fetch('NotBefore', nil))
+        parse_date(at_xpath('./saml:Conditions/@NotBefore').try(:value))
       end
 
       def expired_at
-        parse_date(assertion.fetch('Conditions', {}).fetch('NotOnOrAfter', nil))
+        parse_date(at_xpath('./saml:Conditions/@NotOnOrAfter').try(:value))
       end
 
       def audiences
-        Array(assertion['Conditions']['AudienceRestriction']['Audience'])
-      rescue StandardError => error
-        Saml::Kit.logger.error(error)
-        []
+        search('./saml:Conditions/saml:AudienceRestriction/saml:Audience').map(&:text)
       end
 
       def encrypted?
-        @xml_hash.fetch('EncryptedAssertion', nil).present?
+        @encrypted
       end
 
       def decryptable?
@@ -91,7 +80,7 @@ module Saml
       end
 
       def present?
-        assertion.present?
+        @node.present?
       end
 
       def to_xml(pretty: false)
@@ -102,19 +91,10 @@ module Saml
 
       attr_reader :configuration
 
-      def assertion
-        @assertion ||=
-          begin
-            result = (hash_from(@node)['Response'] || {})['Assertion']
-            return result if result.is_a?(Hash)
-            {}
-          end
-      end
-
       def decrypt!(decryptor)
-        return unless encrypted?
-
-        encrypted_assertion = @node.at_xpath('./xmlenc:EncryptedData', Saml::Kit::Document::NAMESPACES)
+        encrypted_assertion = at_xpath('./xmlenc:EncryptedData')
+        @encrypted = encrypted_assertion.present?
+        return unless @encrypted
         @node = decryptor.decrypt_node(encrypted_assertion)
       rescue Xml::Kit::DecryptionError => error
         @cannot_decrypt = true
@@ -151,12 +131,12 @@ module Saml
       end
 
       def at_xpath(xpath)
+        return unless @node
         @node.at_xpath(xpath, Saml::Kit::Document::NAMESPACES)
       end
 
-      def hash_from(node)
-        return {} if node.nil?
-        Hash.from_xml(node.document.root.to_s) || {}
+      def search(xpath)
+        @node.search(xpath, Saml::Kit::Document::NAMESPACES)
       end
     end
   end
lib/saml/kit/authentication_request.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # This class can be used to parse a SAML AuthnRequest or generate one.
@@ -31,15 +33,19 @@ module Saml
       # Extract the AssertionConsumerServiceURL from the AuthnRequest
       #    <samlp:AuthnRequest AssertionConsumerServiceURL="https://carroll.com/acs"></samlp:AuthnRequest>
       def assertion_consumer_service_url
-        to_h[name]['AssertionConsumerServiceURL']
+        at_xpath('./*/@AssertionConsumerServiceURL').try(:value)
+      end
+
+      def name_id_format
+        name_id_policy
       end
 
       # Extract the NameIDPolicy from the AuthnRequest
       #    <samlp:AuthnRequest>
       #      <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
       #    </samlp:AuthnRequest>
-      def name_id_format
-        to_h[name]['NameIDPolicy']['Format']
+      def name_id_policy
+        at_xpath('./*/samlp:NameIDPolicy/@Format').try(:value)
       end
 
       # Generate a Response for a specific user.
lib/saml/kit/bindings.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'saml/kit/bindings/binding'
 require 'saml/kit/bindings/http_post'
 require 'saml/kit/bindings/http_redirect'
lib/saml/kit/buildable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Buildable
lib/saml/kit/builders.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'saml/kit/xml_templatable'
 require 'saml/kit/builders/assertion'
 require 'saml/kit/builders/authentication_request'
lib/saml/kit/composite_metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     class CompositeMetadata < Metadata # :nodoc:
@@ -14,7 +16,7 @@ module Saml
 
       def services(type)
         xpath = map { |x| "//md:EntityDescriptor/md:#{x.name}/md:#{type}" }.join('|')
-        document.find_all(xpath).map do |item|
+        search(xpath).map do |item|
           binding = item.attribute('Binding').value
           location = item.attribute('Location').value
           Saml::Kit::Bindings.create_for(binding, location)
lib/saml/kit/configuration.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # This class represents the main configuration that is use for generating SAML documents.
lib/saml/kit/default_registry.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # The default metadata registry is used to fetch the metadata associated with an issuer or entity id.
lib/saml/kit/document.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     class Document
@@ -29,27 +31,27 @@ module Saml
 
       # Returns the ID for the SAML document.
       def id
-        root.fetch('ID', nil)
+        at_xpath('./*/@ID').try(:value)
       end
 
       # Returns the Issuer for the SAML document.
       def issuer
-        root.fetch('Issuer', nil)
+        at_xpath('./*/saml:Issuer').try(:text)
       end
 
       # Returns the Version of the SAML document.
       def version
-        root.fetch('Version', {})
+        at_xpath('./*/@Version').try(:value)
       end
 
       # Returns the Destination of the SAML document.
       def destination
-        root.fetch('Destination', nil)
+        at_xpath('./*/@Destination').try(:value)
       end
 
       # Returns the Destination of the SAML document.
       def issue_instant
-        Time.parse(root['IssueInstant'])
+        Time.parse(at_xpath('./*/@IssueInstant').try(:value))
       end
 
       # Returns the SAML document returned as a Hash.
@@ -102,15 +104,12 @@ module Saml
         # @param xml [String] the raw xml string.
         # @param configuration [Saml::Kit::Configuration] the configuration to use for unpacking the document.
         def to_saml_document(xml, configuration: Saml::Kit.configuration)
-          xml_document = ::Xml::Kit::Document.new(xml, namespaces: {
-                                                    "samlp": ::Saml::Kit::Namespaces::PROTOCOL
-                                                  })
           constructor = {
             'AuthnRequest' => Saml::Kit::AuthenticationRequest,
             'LogoutRequest' => Saml::Kit::LogoutRequest,
             'LogoutResponse' => Saml::Kit::LogoutResponse,
             'Response' => Saml::Kit::Response,
-          }[xml_document.find_by(XPATH).name] || InvalidDocument
+          }[Nokogiri::XML(xml).at_xpath(XPATH, "samlp": ::Saml::Kit::Namespaces::PROTOCOL).name] || InvalidDocument
           constructor.new(xml, configuration: configuration)
         rescue StandardError => error
           Saml::Kit.logger.error(error)
@@ -138,10 +137,6 @@ module Saml
 
       attr_reader :content, :name, :configuration
 
-      def root
-        to_h.fetch(name, {})
-      end
-
       def must_match_xsd
         matches_xsd?(PROTOCOL_XSD)
       end
@@ -151,7 +146,7 @@ module Saml
       end
 
       def expected_type?
-        to_h[name].present?
+        at_xpath("./samlp:#{name}").present?
       end
 
       def must_be_valid_version
lib/saml/kit/identity_provider_metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # This class is used to parse the IDPSSODescriptor from a SAML metadata document.
@@ -38,7 +40,7 @@ module Saml
       # Returns the IDPSSODescriptor/@WantAuthnRequestsSigned attribute.
       def want_authn_requests_signed
         xpath = "/md:EntityDescriptor/md:#{name}"
-        attribute = document.find_by(xpath).attribute('WantAuthnRequestsSigned')
+        attribute = at_xpath(xpath).attribute('WantAuthnRequestsSigned')
         return true if attribute.nil?
         attribute.text.casecmp('true').zero?
       end
@@ -57,7 +59,7 @@ module Saml
 
       # Returns each of the Attributes in the metadata.
       def attributes
-        document.find_all("/md:EntityDescriptor/md:#{name}/saml:Attribute").map do |item|
+        search("/md:EntityDescriptor/md:#{name}/saml:Attribute").map do |item|
           {
             format: item.attribute('NameFormat').try(:value),
             name: item.attribute('Name').value,
lib/saml/kit/invalid_document.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # {include:file:spec/saml/invalid_document_spec.rb}
lib/saml/kit/logout_request.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # This class can be used to parse a LogoutRequest SAML document.
@@ -36,7 +38,11 @@ module Saml
 
       # Returns the NameID value.
       def name_id
-        to_h[name]['NameID']
+        at_xpath('./*/saml:NameID').try(:text)
+      end
+
+      def name_id_format
+        at_xpath('./*/saml:NameID/@Format').try(:value)
       end
 
       # Generates a Serialized LogoutResponse using the encoding rules for the specified binding.
lib/saml/kit/logout_response.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # This class is used to parse a LogoutResponse SAML document.
lib/saml/kit/metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # The Metadata object can be used to parse an XML string of metadata.
@@ -29,11 +31,11 @@ module Saml
       include Buildable
       METADATA_XSD = File.expand_path('./xsd/saml-schema-metadata-2.0.xsd', File.dirname(__FILE__)).freeze
       NAMESPACES = {
-        "NameFormat": Namespaces::ATTR_SPLAT,
-        "ds": ::Xml::Kit::Namespaces::XMLDSIG,
-        "md": Namespaces::METADATA,
-        "saml": Namespaces::ASSERTION,
-        "samlp": Namespaces::PROTOCOL,
+        NameFormat: Namespaces::ATTR_SPLAT,
+        ds: ::Xml::Kit::Namespaces::XMLDSIG,
+        md: Namespaces::METADATA,
+        saml: Namespaces::ASSERTION,
+        samlp: Namespaces::PROTOCOL,
       }.freeze
 
       validates_presence_of :metadata
@@ -50,36 +52,34 @@ module Saml
 
       # Returns the /EntityDescriptor/@entityID
       def entity_id
-        document.find_by('/md:EntityDescriptor/@entityID').value
+        at_xpath('/md:EntityDescriptor/@entityID').try(:value)
       end
 
       # Returns the supported NameIDFormats.
       def name_id_formats
-        document.find_all("/md:EntityDescriptor/md:#{name}/md:NameIDFormat").map(&:text)
+        search("/md:EntityDescriptor/md:#{name}/md:NameIDFormat").map(&:text)
       end
 
       # Returns the Organization Name
       def organization_name
-        document.find_by('/md:EntityDescriptor/md:Organization/md:OrganizationName').try(:text)
+        at_xpath('/md:EntityDescriptor/md:Organization/md:OrganizationName').try(:text)
       end
 
       # Returns the Organization URL
       def organization_url
-        document.find_by('/md:EntityDescriptor/md:Organization/md:OrganizationURL').try(:text)
+        at_xpath('/md:EntityDescriptor/md:Organization/md:OrganizationURL').try(:text)
       end
 
       # Returns the Company
       def contact_person_company
-        document.find_by('/md:EntityDescriptor/md:ContactPerson/md:Company').try(:text)
+        at_xpath('/md:EntityDescriptor/md:ContactPerson/md:Company').try(:text)
       end
 
       # Returns each of the X509 certificates.
       def certificates
-        @certificates ||= document.find_all("/md:EntityDescriptor/md:#{name}/md:KeyDescriptor").map do |item|
-          cert = item.at_xpath('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', NAMESPACES).text
-          attribute = item.attribute('use')
-          use = attribute.nil? ? nil : item.attribute('use').value
-          ::Xml::Kit::Certificate.new(cert, use: use)
+        @certificates ||= search("/md:EntityDescriptor/md:#{name}/md:KeyDescriptor").map do |item|
+          cert = item.at_xpath('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', 'ds' => ::Xml::Kit::Namespaces::XMLDSIG).try(:text)
+          ::Xml::Kit::Certificate.new(cert, use: item.attribute('use').try(:value))
         end
       end
 
@@ -97,7 +97,7 @@ module Saml
       #
       # @param type [String] the type of service. .E.g. `AssertionConsumerServiceURL`
       def services(type)
-        document.find_all("/md:EntityDescriptor/md:#{name}/md:#{type}").map do |item|
+        search("/md:EntityDescriptor/md:#{name}/md:#{type}").map do |item|
           binding = item.attribute('Binding').value
           location = item.attribute('Location').value
           Saml::Kit::Bindings.create_for(binding, location)
@@ -132,9 +132,7 @@ module Saml
       # @param relay_state [String] the relay state to have echo'd back.
       # @return [Array] Returns an array with a url and Hash of parameters to send to the other party.
       def logout_request_for(user, binding: :http_post, relay_state: nil)
-        builder = Saml::Kit::LogoutRequest.builder(user) do |x|
-          yield x if block_given?
-        end
+        builder = Saml::Kit::LogoutRequest.builder(user) { |x| yield x if block_given? }
         request_binding = single_logout_service_for(binding: binding)
         request_binding.serialize(builder, relay_state: relay_state)
       end
@@ -145,9 +143,7 @@ module Saml
       # @param use [Symbol] the type of certificates to look at. Can be `:signing` or `:encryption`.
       # @return [Xml::Kit::Certificate] returns the matching `{Xml::Kit::Certificate}`
       def matches?(fingerprint, use: :signing)
-        certificates.find do |certificate|
-          certificate.for?(use) && certificate.fingerprint == fingerprint
-        end
+        certificates.find { |x| x.for?(use) && x.fingerprint == fingerprint }
       end
 
       # Returns the XML document converted to a Hash.
@@ -159,7 +155,7 @@ module Saml
       #
       # @param pretty [Symbol] true to return a human friendly version of the XML.
       def to_xml(pretty: false)
-        document.to_xml(pretty: pretty)
+        pretty ? to_nokogiri.to_xml(indent: 2) : @xml
       end
 
       # Returns the XML document as a [String].
@@ -189,13 +185,15 @@ module Saml
         # @param content [String] the raw metadata XML.
         # @return [Saml::Kit::Metadata] the metadata document or subclass.
         def from(content)
-          hash = Hash.from_xml(content)
-          entity_descriptor = hash['EntityDescriptor']
-          if entity_descriptor.key?('SPSSODescriptor') && entity_descriptor.key?('IDPSSODescriptor')
+          document = Nokogiri::XML(content)
+          return unless document.at_xpath('/md:EntityDescriptor', NAMESPACES)
+          sp = document.at_xpath('/md:EntityDescriptor/md:SPSSODescriptor', NAMESPACES)
+          idp = document.at_xpath('/md:EntityDescriptor/md:IDPSSODescriptor', NAMESPACES)
+          if sp && idp
             Saml::Kit::CompositeMetadata.new(content)
-          elsif entity_descriptor.keys.include?('SPSSODescriptor')
+          elsif sp
             Saml::Kit::ServiceProviderMetadata.new(content)
-          elsif entity_descriptor.keys.include?('IDPSSODescriptor')
+          elsif idp
             Saml::Kit::IdentityProviderMetadata.new(content)
           end
         end
@@ -210,16 +208,21 @@ module Saml
 
       attr_reader :xml
 
-      def document
-        @document ||= ::Xml::Kit::Document.new(xml, namespaces: NAMESPACES)
+      # @!visibility private
+      def to_nokogiri
+        @nokogiri ||= Nokogiri::XML(xml)
       end
 
       def at_xpath(xpath)
-        document.find_by(xpath)
+        to_nokogiri.at_xpath(xpath, NAMESPACES)
+      end
+
+      def search(xpath)
+        to_nokogiri.search(xpath, NAMESPACES)
       end
 
       def metadata
-        document.find_by("/md:EntityDescriptor/md:#{name}").present?
+        at_xpath("/md:EntityDescriptor/md:#{name}").present?
       end
 
       def must_contain_descriptor
lib/saml/kit/namespaces.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Namespaces
lib/saml/kit/null_assertion.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     class NullAssertion
lib/saml/kit/requestable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Requestable
lib/saml/kit/respondable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Respondable
@@ -16,12 +18,12 @@ module Saml
 
       # Returns the /Status/StatusCode@Value
       def status_code
-        to_h.fetch(name, {}).fetch('Status', {}).fetch('StatusCode', {}).fetch('Value', nil)
+        at_xpath('./*/samlp:Status/samlp:StatusCode/@Value').try(:value)
       end
 
       # Returns the /InResponseTo attribute.
       def in_response_to
-        to_h.fetch(name, {}).fetch('InResponseTo', nil)
+        at_xpath('./*/@InResponseTo').try(:value)
       end
 
       # Returns true if the Status code is #{Saml::Kit::Namespaces::SUCCESS}
lib/saml/kit/response.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # {include:file:spec/examples/response_spec.rb}
lib/saml/kit/rspec.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
 require 'saml/kit/rspec/have_query_param'
 require 'saml/kit/rspec/have_xpath'
lib/saml/kit/serializable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Serializable
lib/saml/kit/service_provider_metadata.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     # {include:file:spec/examples/service_provider_metadata_spec.rb}
@@ -20,7 +22,7 @@ module Saml
 
       # Returns true when the metadata demands that Assertions must be signed.
       def want_assertions_signed
-        attribute = document.find_by("/md:EntityDescriptor/md:#{name}").attribute('WantAssertionsSigned')
+        attribute = at_xpath("/md:EntityDescriptor/md:#{name}").attribute('WantAssertionsSigned')
         return true if attribute.nil?
         attribute.text.casecmp('true').zero?
       end
lib/saml/kit/signature.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     class Signature
lib/saml/kit/translatable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Translatable
lib/saml/kit/trustable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module Trustable
lib/saml/kit/version.rb
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
-    VERSION = '1.0.9'.freeze
+    VERSION = '1.0.10'.freeze
   end
 end
lib/saml/kit/xml_templatable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module XmlTemplatable
lib/saml/kit/xsd_validatable.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module Saml
   module Kit
     module XsdValidatable
@@ -5,8 +7,7 @@ module Saml
       def matches_xsd?(xsd)
         Dir.chdir(File.dirname(xsd)) do
           xsd = Nokogiri::XML::Schema(IO.read(xsd))
-          document = Nokogiri::XML(to_xml)
-          xsd.validate(document).each do |error|
+          xsd.validate(to_nokogiri).each do |error|
             errors[:base] << error.message
           end
         end
lib/saml/kit.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'saml/kit/version'
 
 require 'active_model'
lib/saml-kit.rb
@@ -1,1 +1,3 @@
+# frozen_string_literal: true
+
 require 'saml/kit'
spec/saml/kit/bindings/binding_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Bindings::Binding do
   subject { described_class.new(binding: Saml::Kit::Bindings::HTTP_ARTIFACT, location: location) }
 
spec/saml/kit/bindings/http_post_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Bindings::HttpPost do
   subject { described_class.new(location: location) }
 
spec/saml/kit/bindings/http_redirect_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Bindings::HttpRedirect do
   subject { described_class.new(location: location) }
 
spec/saml/kit/bindings/url_builder_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Bindings::UrlBuilder do
   describe '#build' do
     let(:xml) { '<xml></xml>' }
spec/saml/kit/builders/authentication_request_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Builders::AuthenticationRequest do
   subject { described_class.new(configuration: configuration) }
 
spec/saml/kit/builders/identity_provider_metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Builders::IdentityProviderMetadata do
   subject { described_class.new(configuration: configuration) }
 
spec/saml/kit/builders/logout_request_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Builders::LogoutRequest do
   subject { described_class.new(user, configuration: configuration) }
 
spec/saml/kit/builders/logout_response_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Builders::LogoutResponse do
   subject { described_class.new(request) }
 
spec/saml/kit/builders/metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Builders::Metadata do
   describe '.build' do
     subject { Saml::Kit::Metadata }
spec/saml/kit/builders/response_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Builders::Response do
   subject { described_class.new(user, request, configuration: configuration) }
 
spec/saml/kit/builders/service_provider_metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Builders::ServiceProviderMetadata do
   subject { described_class.new(configuration: configuration) }
 
spec/saml/kit/assertion_spec.rb
@@ -1,4 +1,23 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Assertion do
+  subject do
+    Saml::Kit::Response.build(user, request) do |x|
+      x.issuer = entity_id
+    end.assertion
+  end
+
+  let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: ::Xml::Kit::Id.generate, issuer: FFaker::Internet.uri('https'), assertion_consumer_service_url: FFaker::Internet.uri('https'), name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
+  let(:user) { User.new(name_id: SecureRandom.uuid, attributes: { id: SecureRandom.uuid }) }
+  let(:entity_id) { FFaker::Internet.uri('https') }
+
+  specify { expect(subject.issuer).to eql(entity_id) }
+  specify { expect(subject.name_id).to eql(user.name_id) }
+  specify { expect(subject.started_at.to_i).to eql(Time.now.utc.to_i) }
+  specify { expect(subject.expired_at.to_i).to eql(Saml::Kit.configuration.session_timeout.since(Time.now).utc.to_i) }
+  specify { expect(subject.attributes).to eql('id' => user.attributes[:id]) }
+  specify { expect(subject.audiences).to match_array([request.issuer]) }
+
   describe '#active?' do
     let(:configuration) do
       Saml::Kit::Configuration.new do |config|
@@ -12,7 +31,7 @@ RSpec.describe Saml::Kit::Assertion do
       travel_to now
       not_on_or_after = configuration.session_timeout.since(now).iso8601
       xml = <<-XML.strip_heredoc
-        <Response>
+      <Response xmlns="#{Saml::Kit::Namespaces::PROTOCOL}">
         <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
          <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
          <Subject>
@@ -32,9 +51,11 @@ RSpec.describe Saml::Kit::Assertion do
            </AuthnContext>
          </AuthnStatement>
         </Assertion>
-        </Response>
+      </Response>
 XML
-      subject = described_class.new(Nokogiri::XML(xml), configuration: configuration)
+      document = Nokogiri::XML(xml)
+      node = document.at_xpath('//saml:Assertion', 'saml' => Saml::Kit::Namespaces::ASSERTION)
+      subject = described_class.new(node, configuration: configuration)
       travel_to((configuration.clock_drift - 1.second).before(now))
       expect(subject).to be_active
       expect(subject).not_to be_expired
@@ -47,7 +68,7 @@ XML
       not_before = now.utc.iso8601
       not_after = configuration.session_timeout.since(now).iso8601
       xml = <<-XML.strip_heredoc
-        <Response>
+      <Response xmlns="#{Saml::Kit::Namespaces::PROTOCOL}">
         <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
          <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
          <Subject>
@@ -67,9 +88,11 @@ XML
            </AuthnContext>
          </AuthnStatement>
         </Assertion>
-        </Response>
+      </Response>
 XML
-      subject = described_class.new(Nokogiri::XML(xml), configuration: configuration)
+      document = Nokogiri::XML(xml)
+      node = document.at_xpath('//saml:Assertion', 'saml' => Saml::Kit::Namespaces::ASSERTION)
+      subject = described_class.new(node, configuration: configuration)
       expect(subject).to be_active
       expect(subject).not_to be_expired
     end
@@ -128,6 +151,21 @@ XML
     end
   end
 
+  describe '#encrypted?' do
+    it 'returns true when encrypted' do
+      key_pair = Xml::Kit::KeyPair.generate(use: :encryption)
+      response = Saml::Kit::Response.build(user, request) do |x|
+        x.encrypt_with(key_pair)
+      end
+      subject = response.assertion([key_pair.private_key])
+      expect(subject).to be_encrypted
+    end
+
+    it 'returns false when not encrypted' do
+      expect(subject).not_to be_encrypted
+    end
+  end
+
   describe '#to_xml' 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) { User.new(attributes: { id: SecureRandom.uuid }) }
spec/saml/kit/authentication_request_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::AuthenticationRequest do
   subject { described_class.new(raw_xml, configuration: configuration) }
 
@@ -22,11 +24,11 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
     end
   end
 
-  it { expect(subject.issuer).to eql(issuer) }
-  it { expect(subject.id).to eql(id) }
-  it { expect(subject.assertion_consumer_service_url).to eql(assertion_consumer_service_url) }
-  it { expect(subject.name_id_format).to eql(name_id_format) }
-  it { expect(subject.destination).to eql(destination) }
+  specify { expect(subject.issuer).to eql(issuer) }
+  specify { expect(subject.id).to eql(id) }
+  specify { expect(subject.assertion_consumer_service_url).to eql(assertion_consumer_service_url) }
+  specify { expect(subject.name_id_format).to eql(name_id_format) }
+  specify { expect(subject.destination).to eql(destination) }
 
   describe '#valid?' do
     let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
spec/saml/kit/bindings_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Bindings do
   describe '.to_symbol' do
     subject { described_class }
spec/saml/kit/composite_metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::CompositeMetadata do
   subject { described_class.new(xml) }
 
spec/saml/kit/configuration_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Configuration do
   describe '#generate_key_pair_for' do
     subject { described_class.new }
spec/saml/kit/default_registry_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::DefaultRegistry do
   subject { described_class.new }
 
spec/saml/kit/document_spec.rb
@@ -1,4 +1,25 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Document do
+  subject do
+    Saml::Kit::AuthenticationRequest.build do |x|
+      x.id = id
+      x.issuer = issuer
+      x.destination = destination
+    end
+  end
+
+  let(:id) { Xml::Kit::Id.generate }
+  let(:issuer) { FFaker::Internet.uri('https') }
+  let(:destination) { FFaker::Internet.uri('https') }
+
+  specify { expect(subject.id).to eql(id) }
+  specify { expect(subject.issuer).to eql(issuer) }
+  specify { expect(subject.version).to eql('2.0') }
+  specify { expect(subject.destination).to eql(destination) }
+  specify { expect(subject.issue_instant.to_i).to eql(Time.now.to_i) }
+  specify { expect(Saml::Kit::AuthenticationRequest.new('blah').id).to be_nil }
+
   describe '.to_saml_document' do
     subject { described_class }
 
spec/saml/kit/identity_provider_metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::IdentityProviderMetadata do
   subject { described_class.new(raw_metadata) }
 
spec/saml/kit/invalid_document_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::InvalidDocument do
   it 'is invalid' do
     subject = described_class.new('<xml></xml>')
spec/saml/kit/kit_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit do
   it 'has a version number' do
     expect(Saml::Kit::VERSION).not_to be nil
spec/saml/kit/logout_request_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::LogoutRequest do
   subject { described_class.build(user, configuration: configuration) }
 
@@ -25,9 +27,7 @@ RSpec.describe Saml::Kit::LogoutRequest do
     expect(subject.issue_instant).to eql(Time.now.utc)
   end
 
-  it 'parses the version' do
-    expect(subject.version).to eql('2.0')
-  end
+  specify { expect(subject.version).to eql('2.0') }
 
   it 'parses the destination' do
     destination = FFaker::Internet.uri('https')
@@ -37,9 +37,8 @@ RSpec.describe Saml::Kit::LogoutRequest do
     expect(subject.destination).to eql(destination)
   end
 
-  it 'parses the name_id' do
-    expect(subject.name_id).to eql(name_id)
-  end
+  specify { expect(subject.name_id).to eql(name_id) }
+  specify { expect(subject.name_id_format).to eql(Saml::Kit::Namespaces::PERSISTENT) }
 
   describe '#valid?' do
     let(:metadata) do
spec/saml/kit/logout_response_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::LogoutResponse do
   it 'exists' do
     expect(described_class).to be(described_class)
spec/saml/kit/metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Metadata do
   describe '.from' do
     subject { described_class }
spec/saml/kit/response_spec.rb
@@ -1,9 +1,17 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Response do
+  subject { described_class.build(user, request) }
+
+  let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: ::Xml::Kit::Id.generate, issuer: FFaker::Internet.uri('https'), assertion_consumer_service_url: FFaker::Internet.uri('https'), name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
+  let(:user) { User.new(attributes: { id: SecureRandom.uuid }) }
+
+  specify { expect(subject.status_code).to eql(Saml::Kit::Namespaces::SUCCESS) }
+  specify { expect(subject.in_response_to).to eql(request.id) }
+
   describe '#valid?' do
     subject { described_class.build(user, request, configuration: configuration) }
 
-    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) { User.new(attributes: { id: SecureRandom.uuid }) }
     let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
     let(:metadata) { instance_double(Saml::Kit::IdentityProviderMetadata) }
 
spec/saml/kit/service_provider_metadata_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::ServiceProviderMetadata do
   let(:entity_id) { FFaker::Internet.uri('https') }
   let(:acs_post_url) { FFaker::Internet.uri('https') }
spec/saml/kit/signature_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 RSpec.describe Saml::Kit::Signature do
   subject { described_class.new(signed_document.at_xpath('//ds:Signature')) }
 
spec/support/rspec_benchmark.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'rspec-benchmark'
 
 RSpec.configure do |config|
spec/support/test_helpers.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 module TestHelpers
   def query_params_from(url)
     Hash[query_for(url).split('&').map { |x| x.split('=', 2) }]
spec/support/user.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class User
   attr_reader :name_id, :attributes
 
spec/spec_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'simplecov'
 SimpleCov.start do
   add_filter '/spec/'
.rubocop.yml
@@ -70,6 +70,9 @@ Naming/FileName:
 Style/Documentation:
   Enabled: false
 
+Style/EachWithObject:
+  Enabled: false
+
 Style/StringLiterals:
   EnforcedStyle: 'single_quotes'
 
Gemfile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 source 'https://rubygems.org'
 
 git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
Rakefile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require 'bundler/gem_tasks'
 require 'rspec/core/rake_task'
 
saml-kit.gemspec
@@ -1,4 +1,6 @@
 
+# frozen_string_literal: true
+
 lib = File.expand_path('../lib', __FILE__)
 $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
 require 'saml/kit/version'