Commit dff7ad2

mo <mo.khan@gmail.com>
2017-10-25 21:16:34
add service provider metadata builder.
1 parent 1030548
lib/saml/kit/service_provider_metadata.rb
@@ -0,0 +1,55 @@
+module Saml
+  module Kit
+    class ServiceProviderMetadata
+      def initialize(xml)
+        @xml = xml
+      end
+
+      def to_xml
+        @xml
+      end
+
+      class Builder
+        attr_accessor :id, :entity_id, :acs_url
+
+        def initialize
+          @id = SecureRandom.uuid
+        end
+
+        def to_xml
+          xml = ::Builder::XmlMarkup.new
+          xml.instruct!
+          xml.EntityDescriptor entity_descriptor_options do
+            xml.tag! "md:SPSSODescriptor", descriptor_options do
+              xml.tag! "md:NameIDFormat", Namespaces::Formats::NameId::PERSISTENT
+              xml.tag! "md:AssertionConsumerService", Binding: Namespaces::Bindings::POST, Location: acs_url, index: "0", isDefault: "true"
+            end
+          end
+          xml.target!
+        end
+
+        def build
+          ServiceProviderMetadata.new(to_xml)
+        end
+
+        private
+
+        def entity_descriptor_options
+          {
+            'xmlns:md': Namespaces::METADATA,
+            ID: "_#{id}",
+            entityID: entity_id,
+          }
+        end
+
+        def descriptor_options
+          {
+            AuthnRequestsSigned: "true",
+            WantAssertionsSigned: "true",
+            protocolSupportEnumeration: Namespaces::PROTOCOL,
+          }
+        end
+      end
+    end
+  end
+end
lib/saml/kit.rb
@@ -12,6 +12,7 @@ require "saml/kit/request"
 require "saml/kit/response"
 require "saml/kit/service_provider_registry"
 require "saml/kit/identity_provider_metadata"
+require "saml/kit/service_provider_metadata"
 
 module Saml
   module Kit
spec/saml/service_provider_metadata_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+RSpec.describe Saml::Kit::ServiceProviderMetadata do
+  describe described_class::Builder do
+    let(:entity_id) { FFaker::Movie.title }
+    let(:acs_url) { "https://#{FFaker::Internet.domain_name}/acs" }
+
+    <<-XML
+<?xml version="1.0" encoding="UTF-8"?>
+<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
+  ID="_a94ad660-23cc-4491-8fe0-1429b7f5a6d8"
+  entityID="https://service.dev/metadata">
+  <md:SPSSODescriptor
+    AuthnRequestsSigned="true"
+    WantAssertionsSigned="true"
+    protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+    <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
+    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://service.dev/acs" index="0" isDefault="true"/>
+  </md:SPSSODescriptor>
+</md:EntityDescriptor>
+    XML
+    it 'builds the service provider metadata' do
+      subject.entity_id = entity_id
+      subject.acs_url = acs_url
+      result = Hash.from_xml(subject.build.to_xml)
+
+      expect(result['EntityDescriptor']['xmlns:md']).to eql("urn:oasis:names:tc:SAML:2.0:metadata")
+      expect(result['EntityDescriptor']['ID']).to be_present
+      expect(result['EntityDescriptor']['entityID']).to eql(entity_id)
+      expect(result['EntityDescriptor']['SPSSODescriptor']['AuthnRequestsSigned']).to eql('true')
+      expect(result['EntityDescriptor']['SPSSODescriptor']['WantAssertionsSigned']).to eql('true')
+      expect(result['EntityDescriptor']['SPSSODescriptor']['protocolSupportEnumeration']).to eql('urn:oasis:names:tc:SAML:2.0:protocol')
+      expect(result['EntityDescriptor']['SPSSODescriptor']['NameIDFormat']).to eql("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent")
+      expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['Binding']).to eql("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
+      expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['Location']).to eql(acs_url)
+      expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['isDefault']).to eql('true')
+      expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['index']).to eql('0')
+    end
+  end
+end