Commit 0e1afd6

mo <mo.khan@gmail.com>
2018-02-17 00:11:59
use active_support heredoc.
1 parent e562597
spec/saml/kit/assertion_spec.rb
@@ -11,28 +11,28 @@ RSpec.describe Saml::Kit::Assertion do
       now = Time.current
       travel_to now
       not_on_or_after = configuration.session_timeout.since(now).iso8601
-      xml = <<-XML
-<Response>
-<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
- <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
- <Subject>
-   <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
-   <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
-     <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_on_or_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
-   </SubjectConfirmation>
- </Subject>
- <Conditions NotBefore="#{now.utc.iso8601}" NotOnOrAfter="#{not_on_or_after}">
-   <AudienceRestriction>
-     <Audience>#{FFaker::Internet.uri('https')}</Audience>
-   </AudienceRestriction>
- </Conditions>
- <AuthnStatement AuthnInstant="#{now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_on_or_after}">
-   <AuthnContext>
-     <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
-   </AuthnContext>
- </AuthnStatement>
-</Assertion>
-</Response>
+      xml = <<-XML.strip_heredoc
+        <Response>
+        <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
+         <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
+         <Subject>
+           <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
+           <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
+             <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_on_or_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
+           </SubjectConfirmation>
+         </Subject>
+         <Conditions NotBefore="#{now.utc.iso8601}" NotOnOrAfter="#{not_on_or_after}">
+           <AudienceRestriction>
+             <Audience>#{FFaker::Internet.uri('https')}</Audience>
+           </AudienceRestriction>
+         </Conditions>
+         <AuthnStatement AuthnInstant="#{now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_on_or_after}">
+           <AuthnContext>
+             <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
+           </AuthnContext>
+         </AuthnStatement>
+        </Assertion>
+        </Response>
 XML
       subject = described_class.new(Nokogiri::XML(xml), configuration: configuration)
       travel_to (configuration.clock_drift - 1.second).before(now)
@@ -46,28 +46,28 @@ XML
       travel_to now
       not_before = now.utc.iso8601
       not_after = configuration.session_timeout.since(now).iso8601
-      xml = <<-XML
-<Response>
-<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
- <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
- <Subject>
-   <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
-   <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
-     <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
-   </SubjectConfirmation>
- </Subject>
- <Conditions NotBefore="#{not_before}" NotOnOrAfter="#{not_after}">
-   <AudienceRestriction>
-     <Audience>#{FFaker::Internet.uri('https')}</Audience>
-   </AudienceRestriction>
- </Conditions>
- <AuthnStatement AuthnInstant="#{now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_after}">
-   <AuthnContext>
-     <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
-   </AuthnContext>
- </AuthnStatement>
-</Assertion>
-</Response>
+      xml = <<-XML.strip_heredoc
+        <Response>
+        <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
+         <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
+         <Subject>
+           <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
+           <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
+             <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
+           </SubjectConfirmation>
+         </Subject>
+         <Conditions NotBefore="#{not_before}" NotOnOrAfter="#{not_after}">
+           <AudienceRestriction>
+             <Audience>#{FFaker::Internet.uri('https')}</Audience>
+           </AudienceRestriction>
+         </Conditions>
+         <AuthnStatement AuthnInstant="#{now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_after}">
+           <AuthnContext>
+             <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
+           </AuthnContext>
+         </AuthnStatement>
+        </Assertion>
+        </Response>
 XML
       subject = described_class.new(Nokogiri::XML(xml), configuration: configuration)
       expect(subject).to be_active
@@ -84,28 +84,28 @@ XML
     it 'returns true when the assertion is present' do
       not_before = Time.now.utc.iso8601
       not_after = 10.minutes.from_now.iso8601
-      xml = <<-XML
-<Response>
-<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{Time.now.iso8601}" Version="2.0">
- <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
- <Subject>
-   <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
-   <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
-     <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
-   </SubjectConfirmation>
- </Subject>
- <Conditions NotBefore="#{not_before}" NotOnOrAfter="#{not_after}">
-   <AudienceRestriction>
-     <Audience>#{FFaker::Internet.uri('https')}</Audience>
-   </AudienceRestriction>
- </Conditions>
- <AuthnStatement AuthnInstant="#{Time.now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_after}">
-   <AuthnContext>
-     <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
-   </AuthnContext>
- </AuthnStatement>
-</Assertion>
-</Response>
+      xml = <<-XML.strip_heredoc
+        <Response>
+        <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{Time.now.iso8601}" Version="2.0">
+         <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
+         <Subject>
+           <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
+           <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
+             <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
+           </SubjectConfirmation>
+         </Subject>
+         <Conditions NotBefore="#{not_before}" NotOnOrAfter="#{not_after}">
+           <AudienceRestriction>
+             <Audience>#{FFaker::Internet.uri('https')}</Audience>
+           </AudienceRestriction>
+         </Conditions>
+         <AuthnStatement AuthnInstant="#{Time.now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_after}">
+           <AuthnContext>
+             <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
+           </AuthnContext>
+         </AuthnStatement>
+        </Assertion>
+        </Response>
 XML
       subject = described_class.new(Nokogiri::XML(xml))
       expect(subject).to be_present
spec/saml/kit/authentication_request_spec.rb
@@ -95,11 +95,11 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
 
     it 'validates a request without a signature' do
       now = Time.now.utc
-      raw_xml = <<-XML
-<samlp:AuthnRequest AssertionConsumerServiceURL='#{assertion_consumer_service_url}' ID='#{Xml::Kit::Id.generate}' IssueInstant='#{now.iso8601}' Version='2.0' xmlns:saml='#{Saml::Kit::Namespaces::ASSERTION}' xmlns:samlp='#{Saml::Kit::Namespaces::PROTOCOL}'>
-  <saml:Issuer>#{issuer}</saml:Issuer>
-  <samlp:NameIDPolicy AllowCreate='true' Format='#{Saml::Kit::Namespaces::EMAIL_ADDRESS}'/>
-</samlp:AuthnRequest>
+      raw_xml = <<-XML.strip_heredoc
+        <samlp:AuthnRequest AssertionConsumerServiceURL='#{assertion_consumer_service_url}' ID='#{Xml::Kit::Id.generate}' IssueInstant='#{now.iso8601}' Version='2.0' xmlns:saml='#{Saml::Kit::Namespaces::ASSERTION}' xmlns:samlp='#{Saml::Kit::Namespaces::PROTOCOL}'>
+          <saml:Issuer>#{issuer}</saml:Issuer>
+          <samlp:NameIDPolicy AllowCreate='true' Format='#{Saml::Kit::Namespaces::EMAIL_ADDRESS}'/>
+        </samlp:AuthnRequest>
       XML
 
       subject = described_class.new(raw_xml, configuration: configuration)
@@ -109,11 +109,11 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
 
     it 'is valid when there is no signature, and the issuer is registered' do
       now = Time.now.utc
-      raw_xml = <<-XML
-<samlp:AuthnRequest AssertionConsumerServiceURL='#{assertion_consumer_service_url}' ID='#{Xml::Kit::Id.generate}' IssueInstant='#{now.iso8601}' Version='2.0' xmlns:saml='#{Saml::Kit::Namespaces::ASSERTION}' xmlns:samlp='#{Saml::Kit::Namespaces::PROTOCOL}'>
-  <saml:Issuer>#{issuer}</saml:Issuer>
-  <samlp:NameIDPolicy AllowCreate='true' Format='#{Saml::Kit::Namespaces::PERSISTENT}'/>
-</samlp:AuthnRequest>
+      raw_xml = <<-XML.strip_heredoc
+        <samlp:AuthnRequest AssertionConsumerServiceURL='#{assertion_consumer_service_url}' ID='#{Xml::Kit::Id.generate}' IssueInstant='#{now.iso8601}' Version='2.0' xmlns:saml='#{Saml::Kit::Namespaces::ASSERTION}' xmlns:samlp='#{Saml::Kit::Namespaces::PROTOCOL}'>
+          <saml:Issuer>#{issuer}</saml:Issuer>
+          <samlp:NameIDPolicy AllowCreate='true' Format='#{Saml::Kit::Namespaces::PERSISTENT}'/>
+        </samlp:AuthnRequest>
       XML
 
       allow(registry).to receive(:metadata_for).with(issuer).and_return(metadata)
@@ -123,11 +123,11 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
 
     it 'is invalid when there is no signature, and the issuer is not registered' do
       now = Time.now.utc
-      raw_xml = <<-XML
-<samlp:AuthnRequest AssertionConsumerServiceURL='#{assertion_consumer_service_url}' ID='#{Xml::Kit::Id.generate}' IssueInstant='#{now.iso8601}' Version='2.0' xmlns:saml='#{Saml::Kit::Namespaces::ASSERTION}' xmlns:samlp='#{Saml::Kit::Namespaces::PROTOCOL}'>
-  <saml:Issuer>#{issuer}</saml:Issuer>
-  <samlp:NameIDPolicy AllowCreate='true' Format='#{Saml::Kit::Namespaces::PERSISTENT}'/>
-</samlp:AuthnRequest>
+      raw_xml = <<-XML.strip_heredoc
+        <samlp:AuthnRequest AssertionConsumerServiceURL='#{assertion_consumer_service_url}' ID='#{Xml::Kit::Id.generate}' IssueInstant='#{now.iso8601}' Version='2.0' xmlns:saml='#{Saml::Kit::Namespaces::ASSERTION}' xmlns:samlp='#{Saml::Kit::Namespaces::PROTOCOL}'>
+          <saml:Issuer>#{issuer}</saml:Issuer>
+          <samlp:NameIDPolicy AllowCreate='true' Format='#{Saml::Kit::Namespaces::PERSISTENT}'/>
+        </samlp:AuthnRequest>
       XML
 
       allow(registry).to receive(:metadata_for).with(issuer).and_return(nil)
spec/saml/kit/composite_metadata_spec.rb
@@ -13,57 +13,57 @@ RSpec.describe Saml::Kit::CompositeMetadata do
   let(:idp_signing_certificate) { ::Xml::Kit::KeyPair.generate(use: :signing).certificate }
   let(:idp_encryption_certificate) { ::Xml::Kit::KeyPair.generate(use: :encryption).certificate }
   let(:xml) do
-    <<-XML
-<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
-  <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
-    <KeyDescriptor use="signing">
-      <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
-        <X509Data>
-          <X509Certificate>#{sp_signing_certificate.stripped}</X509Certificate>
-        </X509Data>
-      </KeyInfo>
-    </KeyDescriptor>
-    <KeyDescriptor use="encryption">
-      <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
-        <X509Data>
-          <X509Certificate>#{sp_encryption_certificate.stripped}</X509Certificate>
-        </X509Data>
-      </KeyInfo>
-    </KeyDescriptor>
-    <SingleLogoutService Binding="#{post_binding}" Location="#{sp_logout_service}"/>
-    <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
-    <AssertionConsumerService Binding="#{post_binding}" Location="#{assertion_consumer_service}" index="0" isDefault="true"/>
-  </SPSSODescriptor>
-  <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
-    <KeyDescriptor use="signing">
-      <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
-        <X509Data>
-          <X509Certificate>#{idp_signing_certificate.stripped}</X509Certificate>
-        </X509Data>
-      </KeyInfo>
-    </KeyDescriptor>
-    <KeyDescriptor use="encryption">
-      <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
-        <X509Data>
-          <X509Certificate>#{idp_encryption_certificate.stripped}</X509Certificate>
-        </X509Data>
-      </KeyInfo>
-    </KeyDescriptor>
-    <SingleLogoutService Binding="#{post_binding}" Location="#{idp_logout_service}"/>
-    <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
-    <SingleSignOnService Binding="#{post_binding}" Location="#{sign_on_service}"/>
-    <SingleSignOnService Binding="#{redirect_binding}" Location="#{sign_on_service}"/>
-    <Attribute xmlns="#{Saml::Kit::Namespaces::ASSERTION}" Name="id" ></Attribute>
-  </IDPSSODescriptor>
-  <Organization>
-    <OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
-    <OrganizationDisplayName xml:lang="en">Acme, Inc</OrganizationDisplayName>
-    <OrganizationURL xml:lang="en">http://localhost:5000/</OrganizationURL>
-  </Organization>
-  <ContactPerson contactType="technical">
-    <Company>mailto:hi@example.com</Company>
-  </ContactPerson>
-</EntityDescriptor>
+    <<-XML.strip_heredoc
+      <EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
+        <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
+          <KeyDescriptor use="signing">
+            <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
+              <X509Data>
+                <X509Certificate>#{sp_signing_certificate.stripped}</X509Certificate>
+              </X509Data>
+            </KeyInfo>
+          </KeyDescriptor>
+          <KeyDescriptor use="encryption">
+            <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
+              <X509Data>
+                <X509Certificate>#{sp_encryption_certificate.stripped}</X509Certificate>
+              </X509Data>
+            </KeyInfo>
+          </KeyDescriptor>
+          <SingleLogoutService Binding="#{post_binding}" Location="#{sp_logout_service}"/>
+          <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
+          <AssertionConsumerService Binding="#{post_binding}" Location="#{assertion_consumer_service}" index="0" isDefault="true"/>
+        </SPSSODescriptor>
+        <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
+          <KeyDescriptor use="signing">
+            <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
+              <X509Data>
+                <X509Certificate>#{idp_signing_certificate.stripped}</X509Certificate>
+              </X509Data>
+            </KeyInfo>
+          </KeyDescriptor>
+          <KeyDescriptor use="encryption">
+            <KeyInfo xmlns="#{::Xml::Kit::Namespaces::XMLDSIG}">
+              <X509Data>
+                <X509Certificate>#{idp_encryption_certificate.stripped}</X509Certificate>
+              </X509Data>
+            </KeyInfo>
+          </KeyDescriptor>
+          <SingleLogoutService Binding="#{post_binding}" Location="#{idp_logout_service}"/>
+          <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
+          <SingleSignOnService Binding="#{post_binding}" Location="#{sign_on_service}"/>
+          <SingleSignOnService Binding="#{redirect_binding}" Location="#{sign_on_service}"/>
+          <Attribute xmlns="#{Saml::Kit::Namespaces::ASSERTION}" Name="id" ></Attribute>
+        </IDPSSODescriptor>
+        <Organization>
+          <OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
+          <OrganizationDisplayName xml:lang="en">Acme, Inc</OrganizationDisplayName>
+          <OrganizationURL xml:lang="en">http://localhost:5000/</OrganizationURL>
+        </Organization>
+        <ContactPerson contactType="technical">
+          <Company>mailto:hi@example.com</Company>
+        </ContactPerson>
+      </EntityDescriptor>
     XML
   end
 
spec/saml/kit/default_registry_spec.rb
@@ -44,28 +44,28 @@ RSpec.describe Saml::Kit::DefaultRegistry do
     end
 
     it 'registers metadata that serves as both an IDP and SP' do
-      xml = <<-XML
-<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
-  <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
-    <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
-    <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
-    <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}" index="0" isDefault="true"/>
-  </SPSSODescriptor>
-  <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
-    <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
-    <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
-    <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
-    <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri('https')}"/>
-  </IDPSSODescriptor>
-  <Organization>
-    <OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
-    <OrganizationDisplayName xml:lang="en">Acme, Inc</OrganizationDisplayName>
-    <OrganizationURL xml:lang="en">http://localhost:5000/</OrganizationURL>
-  </Organization>
-  <ContactPerson contactType="technical">
-    <Company>mailto:hi@example.com</Company>
-  </ContactPerson>
-</EntityDescriptor>
+      xml = <<-XML.strip_heredoc
+        <EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
+          <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
+            <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+            <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
+            <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}" index="0" isDefault="true"/>
+          </SPSSODescriptor>
+          <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
+            <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+            <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
+            <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+            <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri('https')}"/>
+          </IDPSSODescriptor>
+          <Organization>
+            <OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
+            <OrganizationDisplayName xml:lang="en">Acme, Inc</OrganizationDisplayName>
+            <OrganizationURL xml:lang="en">http://localhost:5000/</OrganizationURL>
+          </Organization>
+          <ContactPerson contactType="technical">
+            <Company>mailto:hi@example.com</Company>
+          </ContactPerson>
+        </EntityDescriptor>
       XML
       stub_request(:get, url).to_return(status: 200, body: xml)
       subject.register_url(url)
spec/saml/kit/metadata_spec.rb
@@ -13,28 +13,28 @@ RSpec.describe Saml::Kit::Metadata do
     end
 
     it 'returns a composite' do
-      xml = <<-XML
-<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{Xml::Kit::Id.generate}" entityID="#{FFaker::Internet.uri('https')}">
-  <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
-    <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
-    <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
-    <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}" index="0" isDefault="true"/>
-  </SPSSODescriptor>
-  <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
-    <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
-    <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
-    <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
-    <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri('https')}"/>
-  </IDPSSODescriptor>
-  <Organization>
-    <OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
-    <OrganizationDisplayName xml:lang="en">Acme, Inc</OrganizationDisplayName>
-    <OrganizationURL xml:lang="en">http://localhost:5000/</OrganizationURL>
-  </Organization>
-  <ContactPerson contactType="technical">
-    <Company>mailto:hi@example.com</Company>
-  </ContactPerson>
-</EntityDescriptor>
+      xml = <<-XML.strip_heredoc
+        <EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{Xml::Kit::Id.generate}" entityID="#{FFaker::Internet.uri('https')}">
+          <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
+            <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+            <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
+            <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}" index="0" isDefault="true"/>
+          </SPSSODescriptor>
+          <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
+            <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+            <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
+            <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+            <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri('https')}"/>
+          </IDPSSODescriptor>
+          <Organization>
+            <OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
+            <OrganizationDisplayName xml:lang="en">Acme, Inc</OrganizationDisplayName>
+            <OrganizationURL xml:lang="en">http://localhost:5000/</OrganizationURL>
+          </Organization>
+          <ContactPerson contactType="technical">
+            <Company>mailto:hi@example.com</Company>
+          </ContactPerson>
+        </EntityDescriptor>
       XML
       result = subject.from(xml)
       expect(result).to be_present
spec/saml/kit/response_spec.rb
@@ -146,14 +146,14 @@ RSpec.describe Saml::Kit::Response do
     it 'is invalid' do
       now = Time.now.utc
       destination = FFaker::Internet.uri('https')
-      raw_xml = <<-XML
-<?xml version="1.0"?>
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{Xml::Kit::Id.generate}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{destination}" Consent="#{Saml::Kit::Namespaces::UNSPECIFIED}" InResponseTo="#{request.id}">
-  <Issuer xmlns="#{Saml::Kit::Namespaces::ASSERTION}">#{request.issuer}</Issuer>
-  <samlp:Status>
-    <samlp:StatusCode Value="#{Saml::Kit::Namespaces::RESPONDER_ERROR}"/>
-  </samlp:Status>
-</samlp:Response>
+      raw_xml = <<-XML.strip_heredoc
+        <?xml version="1.0"?>
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{Xml::Kit::Id.generate}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{destination}" Consent="#{Saml::Kit::Namespaces::UNSPECIFIED}" InResponseTo="#{request.id}">
+          <Issuer xmlns="#{Saml::Kit::Namespaces::ASSERTION}">#{request.issuer}</Issuer>
+          <samlp:Status>
+            <samlp:StatusCode Value="#{Saml::Kit::Namespaces::RESPONDER_ERROR}"/>
+          </samlp:Status>
+        </samlp:Response>
       XML
 
       allow(registry).to receive(:metadata_for).with(request.issuer).and_return(metadata)
@@ -264,32 +264,32 @@ RSpec.describe Saml::Kit::Response do
     let(:url) { FFaker::Internet.uri('https') }
 
     it 'returns true when the Assertion is signed' do
-      xml = <<-XML
-<?xml version="1.0"?>
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
-  <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0">
-    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-      <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-        <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
-        <ds:Reference URI="##{id}">
-          <ds:Transforms>
-            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
-            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-          </ds:Transforms>
-          <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
-          <ds:DigestValue></ds:DigestValue>
-        </ds:Reference>
-      </ds:SignedInfo>
-      <ds:SignatureValue></ds:SignatureValue>
-      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
-        <ds:X509Data>
-          <ds:X509Certificate></ds:X509Certificate>
-        </ds:X509Data>
-      </KeyInfo>
-    </ds:Signature>
-  </Assertion>
-</samlp:Response>
+      xml = <<-XML.strip_heredoc
+        <?xml version="1.0"?>
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
+          <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0">
+            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+              <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
+                <ds:Reference URI="##{id}">
+                  <ds:Transforms>
+                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                  </ds:Transforms>
+                  <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
+                  <ds:DigestValue></ds:DigestValue>
+                </ds:Reference>
+              </ds:SignedInfo>
+              <ds:SignatureValue></ds:SignatureValue>
+              <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
+                <ds:X509Data>
+                  <ds:X509Certificate></ds:X509Certificate>
+                </ds:X509Data>
+              </KeyInfo>
+            </ds:Signature>
+          </Assertion>
+        </samlp:Response>
       XML
       subject = described_class.new(xml)
       expect(subject).not_to be_signed
@@ -297,42 +297,42 @@ RSpec.describe Saml::Kit::Response do
     end
 
     it 'returns true when the Response is signed' do
-      xml = <<-XML
-<?xml version="1.0"?>
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
-  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-    <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
-      <ds:Reference URI="##{id}">
-        <ds:Transforms>
-          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
-          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-        </ds:Transforms>
-        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
-        <ds:DigestValue></ds:DigestValue>
-      </ds:Reference>
-    </ds:SignedInfo>
-    <ds:SignatureValue></ds:SignatureValue>
-    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
-      <ds:X509Data>
-        <ds:X509Certificate></ds:X509Certificate>
-      </ds:X509Data>
-    </KeyInfo>
-  </ds:Signature>
-  <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
-</samlp:Response>
+      xml = <<-XML.strip_heredoc
+        <?xml version="1.0"?>
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
+          <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+              <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+              <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
+              <ds:Reference URI="##{id}">
+                <ds:Transforms>
+                  <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+                  <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                </ds:Transforms>
+                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
+                <ds:DigestValue></ds:DigestValue>
+              </ds:Reference>
+            </ds:SignedInfo>
+            <ds:SignatureValue></ds:SignatureValue>
+            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
+              <ds:X509Data>
+                <ds:X509Certificate></ds:X509Certificate>
+              </ds:X509Data>
+            </KeyInfo>
+          </ds:Signature>
+          <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
+        </samlp:Response>
       XML
       subject = described_class.new(xml)
       expect(subject).to be_signed
     end
 
     it 'returns false when there is no signature' do
-      xml = <<-XML
-<?xml version="1.0"?>
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
-  <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
-</samlp:Response>
+      xml = <<-XML.strip_heredoc
+        <?xml version="1.0"?>
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
+          <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
+        </samlp:Response>
       XML
       subject = described_class.new(xml)
       expect(subject).not_to be_signed
@@ -351,32 +351,32 @@ RSpec.describe Saml::Kit::Response do
     end
 
     it 'returns the certificate when the Assertion is signed' do
-      xml = <<-XML
-<?xml version="1.0"?>
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
-  <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0">
-    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-      <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-        <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
-        <ds:Reference URI="##{id}">
-          <ds:Transforms>
-            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
-            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-          </ds:Transforms>
-          <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
-          <ds:DigestValue></ds:DigestValue>
-        </ds:Reference>
-      </ds:SignedInfo>
-      <ds:SignatureValue></ds:SignatureValue>
-      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
-        <ds:X509Data>
-          <ds:X509Certificate>#{certificate.stripped}</ds:X509Certificate>
-        </ds:X509Data>
-      </KeyInfo>
-    </ds:Signature>
-  </Assertion>
-</samlp:Response>
+      xml = <<-XML.strip_heredoc
+        <?xml version="1.0"?>
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
+          <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0">
+            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+              <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
+                <ds:Reference URI="##{id}">
+                  <ds:Transforms>
+                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                  </ds:Transforms>
+                  <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
+                  <ds:DigestValue></ds:DigestValue>
+                </ds:Reference>
+              </ds:SignedInfo>
+              <ds:SignatureValue></ds:SignatureValue>
+              <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
+                <ds:X509Data>
+                  <ds:X509Certificate>#{certificate.stripped}</ds:X509Certificate>
+                </ds:X509Data>
+              </KeyInfo>
+            </ds:Signature>
+          </Assertion>
+        </samlp:Response>
       XML
       subject = described_class.new(xml)
       expect(subject.signature).not_to be_present
@@ -385,42 +385,42 @@ RSpec.describe Saml::Kit::Response do
     end
 
     it 'returns the certificate when the Response is signed' do
-      xml = <<-XML
-<?xml version="1.0"?>
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
-  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-    <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
-      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
-      <ds:Reference URI="##{id}">
-        <ds:Transforms>
-          <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
-          <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
-        </ds:Transforms>
-        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
-        <ds:DigestValue></ds:DigestValue>
-      </ds:Reference>
-    </ds:SignedInfo>
-    <ds:SignatureValue></ds:SignatureValue>
-    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
-      <ds:X509Data>
-        <ds:X509Certificate>#{certificate}</ds:X509Certificate>
-      </ds:X509Data>
-    </KeyInfo>
-  </ds:Signature>
-  <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
-</samlp:Response>
+      xml = <<-XML.strip_heredoc
+        <?xml version="1.0"?>
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
+          <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+            <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+              <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+              <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
+              <ds:Reference URI="##{id}">
+                <ds:Transforms>
+                  <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+                  <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                </ds:Transforms>
+                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
+                <ds:DigestValue></ds:DigestValue>
+              </ds:Reference>
+            </ds:SignedInfo>
+            <ds:SignatureValue></ds:SignatureValue>
+            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
+              <ds:X509Data>
+                <ds:X509Certificate>#{certificate}</ds:X509Certificate>
+              </ds:X509Data>
+            </KeyInfo>
+          </ds:Signature>
+          <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
+        </samlp:Response>
       XML
       subject = described_class.new(xml)
       expect(subject.signature.certificate).to eql(certificate)
     end
 
     it 'returns nil when there is no signature' do
-      xml = <<-XML
-<?xml version="1.0"?>
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
-  <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
-</samlp:Response>
+      xml = <<-XML.strip_heredoc
+        <?xml version="1.0"?>
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{url}" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_#{SecureRandom.uuid}">
+          <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="#{now.iso8601}" Version="2.0"></Assertion>
+        </samlp:Response>
       XML
       subject = described_class.new(xml)
       expect(subject.signature).not_to be_present
@@ -435,34 +435,34 @@ RSpec.describe Saml::Kit::Response do
     let(:email) { FFaker::Internet.email }
     let(:created_at) { DateTime.now }
     let(:assertion) do
-      <<-XML
-<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="2017-11-23T04:33:58Z" Version="2.0">
- <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
- <Subject>
-   <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
-   <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
-     <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="2017-11-23T07:33:58Z" Recipient="https://westyundt.ca/acs"/>
-   </SubjectConfirmation>
- </Subject>
- <Conditions NotBefore="2017-11-23T04:33:58Z" NotOnOrAfter="2017-11-23T07:33:58Z">
-   <AudienceRestriction>
-     <Audience>American Wolves</Audience>
-   </AudienceRestriction>
- </Conditions>
- <AuthnStatement AuthnInstant="2017-11-23T04:33:58Z" SessionIndex="_11d39a7f-1b86-43ed-90d7-68090a857ca8" SessionNotOnOrAfter="2017-11-23T07:33:58Z">
-   <AuthnContext>
-     <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
-   </AuthnContext>
- </AuthnStatement>
- <AttributeStatement>
-   <Attribute Name="email" NameFormat="#{Saml::Kit::Namespaces::URI}">
-     <AttributeValue>#{email}</AttributeValue>
-   </Attribute>
-   <Attribute Name="created_at" NameFormat="#{Saml::Kit::Namespaces::URI}">
-     <AttributeValue>#{created_at.iso8601}</AttributeValue>
-   </Attribute>
- </AttributeStatement>
-</Assertion>
+      <<-XML.strip_heredoc
+        <Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="2017-11-23T04:33:58Z" Version="2.0">
+         <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
+         <Subject>
+           <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
+           <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
+             <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="2017-11-23T07:33:58Z" Recipient="https://westyundt.ca/acs"/>
+           </SubjectConfirmation>
+         </Subject>
+         <Conditions NotBefore="2017-11-23T04:33:58Z" NotOnOrAfter="2017-11-23T07:33:58Z">
+           <AudienceRestriction>
+             <Audience>American Wolves</Audience>
+           </AudienceRestriction>
+         </Conditions>
+         <AuthnStatement AuthnInstant="2017-11-23T04:33:58Z" SessionIndex="_11d39a7f-1b86-43ed-90d7-68090a857ca8" SessionNotOnOrAfter="2017-11-23T07:33:58Z">
+           <AuthnContext>
+             <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
+           </AuthnContext>
+         </AuthnStatement>
+         <AttributeStatement>
+           <Attribute Name="email" NameFormat="#{Saml::Kit::Namespaces::URI}">
+             <AttributeValue>#{email}</AttributeValue>
+           </Attribute>
+           <Attribute Name="created_at" NameFormat="#{Saml::Kit::Namespaces::URI}">
+             <AttributeValue>#{created_at.iso8601}</AttributeValue>
+           </Attribute>
+         </AttributeStatement>
+        </Assertion>
 XML
     end
 
@@ -479,29 +479,29 @@ XML
       iv = cipher.random_iv
       encrypted = cipher.update(assertion) + cipher.final
 
-      xml = <<-XML
-<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" xmlns:saml="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{assertion_consumer_service_url}" InResponseTo="#{Xml::Kit::Id.generate}">
-  <saml:Issuer>#{FFaker::Internet.uri('https')}</saml:Issuer>
-  <samlp:Status>
-    <samlp:StatusCode Value="#{Saml::Kit::Namespaces::SUCCESS}"/>
-  </samlp:Status>
-  <saml:EncryptedAssertion>
-    <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
-    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
-    <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
-      <xenc:EncryptedKey>
-        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
-        <xenc:CipherData>
-          <xenc:CipherValue>#{Base64.encode64(public_key.public_encrypt(key))}</xenc:CipherValue>
-        </xenc:CipherData>
-      </xenc:EncryptedKey>
-    </dsig:KeyInfo>
-    <xenc:CipherData>
-      <xenc:CipherValue>#{Base64.encode64(iv + encrypted)}</xenc:CipherValue>
-    </xenc:CipherData>
-    </xenc:EncryptedData>
-  </saml:EncryptedAssertion>
-</samlp:Response>
+      xml = <<-XML.strip_heredoc
+        <samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" xmlns:saml="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{assertion_consumer_service_url}" InResponseTo="#{Xml::Kit::Id.generate}">
+          <saml:Issuer>#{FFaker::Internet.uri('https')}</saml:Issuer>
+          <samlp:Status>
+            <samlp:StatusCode Value="#{Saml::Kit::Namespaces::SUCCESS}"/>
+          </samlp:Status>
+          <saml:EncryptedAssertion>
+            <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
+            <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+              <xenc:EncryptedKey>
+                <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
+                <xenc:CipherData>
+                  <xenc:CipherValue>#{Base64.encode64(public_key.public_encrypt(key))}</xenc:CipherValue>
+                </xenc:CipherData>
+              </xenc:EncryptedKey>
+            </dsig:KeyInfo>
+            <xenc:CipherData>
+              <xenc:CipherValue>#{Base64.encode64(iv + encrypted)}</xenc:CipherValue>
+            </xenc:CipherData>
+            </xenc:EncryptedData>
+          </saml:EncryptedAssertion>
+        </samlp:Response>
 XML
 
       subject = described_class.new(xml)
spec/saml/kit/service_provider_metadata_spec.rb
@@ -102,14 +102,14 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
     end
 
     it 'is invalid when 0 ACS endpoints are specified' do
-      xml = <<-XML
-<?xml version="1.0" encoding="UTF-8"?>
-<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
-  <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
-    <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
-    <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
-  </SPSSODescriptor>
-</EntityDescriptor>
+      xml = <<-XML.strip_heredoc
+        <?xml version="1.0" encoding="UTF-8"?>
+        <EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
+          <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
+            <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+            <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
+          </SPSSODescriptor>
+        </EntityDescriptor>
       XML
       expect(described_class.new(xml)).to be_invalid
     end
.rubocop.yml
@@ -12,9 +12,6 @@ AllCops:
     - 'vendor/**/*'
   TargetRubyVersion: 2.2
 
-Layout/EndOfLine:
-  EnforcedStyle: lf
-
 Layout/ClassStructure:
   Enabled: true
   Categories:
@@ -31,6 +28,12 @@ Layout/ClassStructure:
       - protected_methods
       - private_methods
 
+Layout/EndOfLine:
+  EnforcedStyle: lf
+
+Layout/IndentHeredoc:
+  EnforcedStyle: active_support
+
 Lint/AmbiguousBlockAssociation:
   Exclude:
     - 'spec/**/*.rb'
@@ -59,8 +62,14 @@ Style/StringLiterals:
 Style/TrailingCommaInLiteral:
   Enabled: false
 
-RSpec/NestedGroups:
-  Max: 7
+RSpec/ExampleLength:
+  Max: 10
+
+RSpec/MultipleExpectations:
+  Max: 5
 
 RSpec/NamedSubject:
   Enabled: false
+
+RSpec/NestedGroups:
+  Max: 7