Commit 04c9b1e

mo <mo.khan@gmail.com>
2017-11-01 21:21:56
parse logout urls.
1 parent 4770d21
lib/saml/kit/identity_provider_metadata.rb
@@ -28,13 +28,6 @@ module Saml
         end
       end
 
-      def single_logout_services
-        xpath = "/md:EntityDescriptor/md:IDPSSODescriptor/md:SingleLogoutService"
-        find_all(xpath).map do |item|
-          { binding: item.attribute("Binding").value, location: item.attribute("Location").value }
-        end
-      end
-
       def attributes
         find_all("/md:EntityDescriptor/md:IDPSSODescriptor/saml:Attribute").map do |item|
           {
lib/saml/kit/metadata.rb
@@ -35,6 +35,16 @@ module Saml
         certificates.find_all { |x| x[:use] == "signing" }
       end
 
+      def single_logout_services
+        xpath = "/md:EntityDescriptor/md:#{descriptor_name}/md:SingleLogoutService"
+        find_all(xpath).map do |item|
+          {
+            binding: item.attribute("Binding").value,
+            location: item.attribute("Location").value,
+          }
+        end
+      end
+
       def to_xml
         @xml
       end
lib/saml/kit/service_provider_metadata.rb
@@ -18,18 +18,23 @@ module Saml
       private
 
       class Builder
-        attr_accessor :id, :entity_id, :acs_urls
+        attr_accessor :id, :entity_id, :acs_urls, :logout_urls
 
         def initialize(configuration = Saml::Kit.configuration)
           @id = SecureRandom.uuid
           @configuration = configuration
           @acs_urls = []
+          @logout_urls = []
         end
 
-        def add_acs_url(url, binding: :post)
+        def add_assertion_consumer_service(url, binding: :post)
           @acs_urls.push(location: url, binding: binding_namespace_for(binding))
         end
 
+        def add_single_logout_service(url, binding: :post)
+          @logout_urls.push(location: url, binding: binding_namespace_for(binding))
+        end
+
         def to_xml
           signature = Signature.new(id)
           xml = ::Builder::XmlMarkup.new
@@ -46,6 +51,9 @@ module Saml
                   isDefault: index == 0 ? true : false,
                 }
               end
+              logout_urls.each do |item|
+                xml.tag! "md:SingleLogoutService", Binding: item[:binding], Location: item[:location]
+              end
               xml.tag! "md:KeyDescriptor", use: "signing" do
                 xml.tag! "ds:KeyInfo", "xmlns:ds": Saml::Kit::Signature::XMLDSIG do
                   xml.tag! "ds:X509Data" do
spec/saml/service_provider_metadata_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
     XML
     it 'builds the service provider metadata' do
       subject.entity_id = entity_id
-      subject.add_acs_url(acs_url, binding: :post)
+      subject.add_assertion_consumer_service(acs_url, binding: :post)
       result = Hash.from_xml(subject.build.to_xml)
 
       expect(result['EntityDescriptor']['xmlns:md']).to eql("urn:oasis:names:tc:SAML:2.0:metadata")
@@ -45,11 +45,15 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
     let(:entity_id) { FFaker::Movie.title }
     let(:acs_post_url) { "https://#{FFaker::Internet.domain_name}/post" }
     let(:acs_redirect_url) { "https://#{FFaker::Internet.domain_name}/redirect" }
+    let(:logout_post_url) { "https://#{FFaker::Internet.domain_name}/post" }
+    let(:logout_redirect_url) { "https://#{FFaker::Internet.domain_name}/redirect" }
     let(:builder) { described_class::Builder.new }
     subject do
       builder.entity_id = entity_id
-      builder.add_acs_url(acs_post_url, binding: :post)
-      builder.add_acs_url(acs_redirect_url, binding: :http_redirect)
+      builder.add_assertion_consumer_service(acs_post_url, binding: :post)
+      builder.add_assertion_consumer_service(acs_redirect_url, binding: :http_redirect)
+      builder.add_single_logout_service(logout_post_url, binding: :post)
+      builder.add_single_logout_service(logout_redirect_url, binding: :http_redirect)
       builder.build
     end
 
@@ -70,5 +74,12 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
         { location: acs_redirect_url, binding: Saml::Kit::Namespaces::Bindings::HTTP_REDIRECT },
       ])
     end
+
+    it 'returns each logout url and binding' do
+      expect(subject.single_logout_services).to match_array([
+        { location: logout_post_url, binding: Saml::Kit::Namespaces::Bindings::POST },
+        { location: logout_redirect_url, binding: Saml::Kit::Namespaces::Bindings::HTTP_REDIRECT },
+      ])
+    end
   end
 end