main
  1# frozen_string_literal: true
  2
  3RSpec.describe Saml::Kit::DefaultRegistry do
  4  subject { described_class.new }
  5
  6  let(:entity_id) { FFaker::Internet.http_url }
  7  let(:service_provider_metadata) do
  8    Saml::Kit::ServiceProviderMetadata.build do |builder|
  9      builder.entity_id = entity_id
 10      builder.add_assertion_consumer_service(FFaker::Internet.uri('https'), binding: :http_post)
 11    end
 12  end
 13  let(:identity_provider_metadata) do
 14    Saml::Kit::IdentityProviderMetadata.build do |builder|
 15      builder.entity_id = entity_id
 16      builder.add_single_sign_on_service(FFaker::Internet.uri('https'), binding: :http_post)
 17    end
 18  end
 19
 20  describe '#metadata_for' do
 21    it 'returns the metadata for the entity_id' do
 22      subject.register(service_provider_metadata)
 23      expect(subject.metadata_for(entity_id)).to eql(service_provider_metadata)
 24    end
 25  end
 26
 27  describe '#register_url' do
 28    let(:url) { FFaker::Internet.http_url }
 29
 30    it 'fetches the SP metadata from a remote url and registers it' do
 31      stub_request(:get, url)
 32        .to_return(status: 200, body: service_provider_metadata.to_xml)
 33      subject.register_url(url)
 34
 35      result = subject.metadata_for(entity_id)
 36      expect(result).to be_present
 37      expect(result).to be_instance_of(Saml::Kit::ServiceProviderMetadata)
 38    end
 39
 40    it 'fetches the IDP metadata from a remote url' do
 41      stub_request(:get, url)
 42        .to_return(status: 200, body: identity_provider_metadata.to_xml)
 43      subject.register_url(url)
 44
 45      result = subject.metadata_for(entity_id)
 46      expect(result).to be_present
 47      expect(result).to be_instance_of(Saml::Kit::IdentityProviderMetadata)
 48    end
 49
 50    it 'registers metadata that serves as both an IDP and SP' do
 51      xml = <<-XML.strip_heredoc
 52        <EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
 53          <SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
 54            <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
 55            <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
 56            <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}" index="0" isDefault="true"/>
 57          </SPSSODescriptor>
 58          <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
 59            <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
 60            <NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
 61            <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
 62            <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri('https')}"/>
 63          </IDPSSODescriptor>
 64          <Organization>
 65            <OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
 66            <OrganizationDisplayName xml:lang="en">Acme, Inc</OrganizationDisplayName>
 67            <OrganizationURL xml:lang="en">http://localhost:5000/</OrganizationURL>
 68          </Organization>
 69          <ContactPerson contactType="technical">
 70            <Company>mailto:hi@example.com</Company>
 71          </ContactPerson>
 72        </EntityDescriptor>
 73      XML
 74      stub_request(:get, url).to_return(status: 200, body: xml)
 75      subject.register_url(url)
 76
 77      result = subject.metadata_for(entity_id)
 78      expect(result).to be_present
 79      expect(result).to be_instance_of(Saml::Kit::CompositeMetadata)
 80    end
 81  end
 82
 83  describe '#register' do
 84    it 'registers the metadata' do
 85      metadata = Saml::Kit::IdentityProviderMetadata.build do |xxx|
 86        xxx.entity_id = FFaker::Internet.uri('https')
 87        xxx.add_single_sign_on_service(FFaker::Internet.uri('https'), binding: :http_post)
 88      end
 89      subject.register(metadata)
 90      expect(subject.metadata_for(metadata.entity_id)).to eql(metadata)
 91    end
 92
 93    it 'raises an error when the metadata is invalid' do
 94      expect do
 95        subject.register(Saml::Kit::IdentityProviderMetadata.build)
 96      end.to raise_error(/Cannot register invalid metadata/)
 97    end
 98
 99    it 'raises an error when the document is not a metadata' do
100      authn_request = Saml::Kit::AuthenticationRequest.build
101      allow(authn_request).to receive(:valid?).and_return(true)
102
103      expect do
104        subject.register(authn_request)
105      end.to raise_error(/Cannot register invalid metadata/)
106    end
107
108    it 'raises an error when the document is nil' do
109      expect do
110        subject.register(nil)
111      end.to raise_error(/Cannot register invalid metadata/)
112    end
113  end
114
115  describe '#each' do
116    it 'yields each registered metadata' do
117      idp = Saml::Kit::IdentityProviderMetadata.build do |xxx|
118        xxx.entity_id = 'idp'
119        xxx.add_single_sign_on_service(FFaker::Internet.uri('https'), binding: :http_post)
120      end
121      sp = Saml::Kit::ServiceProviderMetadata.build do |xxx|
122        xxx.entity_id = 'sp'
123        xxx.add_assertion_consumer_service(FFaker::Internet.uri('https'), binding: :http_post)
124      end
125
126      subject.register(idp)
127      subject.register(sp)
128
129      expect(subject.map(&:to_xml)).to match_array([idp.to_xml, sp.to_xml])
130    end
131  end
132end