Commit 6ab0459
Changed files (5)
lib
saml
spec
lib/saml/kit/builders/identity_provider_metadata.rb
@@ -0,0 +1,103 @@
+module Saml
+ module Kit
+ class IdentityProviderMetadata < Metadata
+ class Builder
+ attr_accessor :id, :organization_name, :organization_url, :contact_email, :entity_id, :attributes, :name_id_formats
+ attr_accessor :want_authn_requests_signed, :sign
+ attr_reader :logout_urls, :single_sign_on_urls
+
+ def initialize(configuration = Saml::Kit.configuration)
+ @id = SecureRandom.uuid
+ @entity_id = configuration.issuer
+ @attributes = []
+ @name_id_formats = [Namespaces::PERSISTENT]
+ @single_sign_on_urls = []
+ @logout_urls = []
+ @configuration = configuration
+ @sign = true
+ @want_authn_requests_signed = true
+ end
+
+ def add_single_sign_on_service(url, binding: :http_post)
+ @single_sign_on_urls.push(location: url, binding: Bindings.binding_for(binding))
+ end
+
+ def add_single_logout_service(url, binding: :http_post)
+ @logout_urls.push(location: url, binding: Bindings.binding_for(binding))
+ end
+
+ def to_xml
+ Signature.sign(sign: sign) do |xml, signature|
+ xml.instruct!
+ xml.EntityDescriptor entity_descriptor_options do
+ signature.template(id)
+ xml.IDPSSODescriptor idp_sso_descriptor_options do
+ if @configuration.signing_certificate_pem.present?
+ xml.KeyDescriptor use: "signing" do
+ xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
+ xml.X509Data do
+ xml.X509Certificate @configuration.stripped_signing_certificate
+ end
+ end
+ end
+ end
+ if @configuration.encryption_certificate_pem.present?
+ xml.KeyDescriptor use: "encryption" do
+ xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
+ xml.X509Data do
+ xml.X509Certificate @configuration.stripped_encryption_certificate
+ end
+ end
+ end
+ end
+ logout_urls.each do |item|
+ xml.SingleLogoutService Binding: item[:binding], Location: item[:location]
+ end
+ name_id_formats.each do |format|
+ xml.NameIDFormat format
+ end
+ single_sign_on_urls.each do |item|
+ xml.SingleSignOnService Binding: item[:binding], Location: item[:location]
+ end
+ attributes.each do |attribute|
+ xml.tag! 'saml:Attribute', Name: attribute
+ end
+ end
+ xml.Organization do
+ xml.OrganizationName organization_name, 'xml:lang': "en"
+ xml.OrganizationDisplayName organization_name, 'xml:lang': "en"
+ xml.OrganizationURL organization_url, 'xml:lang': "en"
+ end
+ xml.ContactPerson contactType: "technical" do
+ xml.Company "mailto:#{contact_email}"
+ end
+ end
+ end
+ end
+
+ def build
+ IdentityProviderMetadata.new(to_xml)
+ end
+
+ private
+
+ def entity_descriptor_options
+ {
+ 'xmlns': Namespaces::METADATA,
+ 'xmlns:ds': Namespaces::XMLDSIG,
+ 'xmlns:saml': Namespaces::ASSERTION,
+ ID: "_#{id}",
+ entityID: entity_id,
+ }
+ end
+
+ def idp_sso_descriptor_options
+ {
+ WantAuthnRequestsSigned: want_authn_requests_signed,
+ protocolSupportEnumeration: Namespaces::PROTOCOL,
+ }
+ end
+ end
+ end
+ end
+end
lib/saml/kit/builders.rb
@@ -1,1 +1,2 @@
require 'saml/kit/builders/authentication_request'
+require 'saml/kit/builders/identity_provider_metadata'
lib/saml/kit/identity_provider_metadata.rb
@@ -28,106 +28,6 @@ module Saml
}
end
end
-
- private
-
- class Builder
- attr_accessor :id, :organization_name, :organization_url, :contact_email, :entity_id, :attributes, :name_id_formats
- attr_accessor :want_authn_requests_signed, :sign
- attr_reader :logout_urls, :single_sign_on_urls
-
- def initialize(configuration = Saml::Kit.configuration)
- @id = SecureRandom.uuid
- @entity_id = configuration.issuer
- @attributes = []
- @name_id_formats = [Namespaces::PERSISTENT]
- @single_sign_on_urls = []
- @logout_urls = []
- @configuration = configuration
- @sign = true
- @want_authn_requests_signed = true
- end
-
- def add_single_sign_on_service(url, binding: :http_post)
- @single_sign_on_urls.push(location: url, binding: Bindings.binding_for(binding))
- end
-
- def add_single_logout_service(url, binding: :http_post)
- @logout_urls.push(location: url, binding: Bindings.binding_for(binding))
- end
-
- def to_xml
- Signature.sign(sign: sign) do |xml, signature|
- xml.instruct!
- xml.EntityDescriptor entity_descriptor_options do
- signature.template(id)
- xml.IDPSSODescriptor idp_sso_descriptor_options do
- if @configuration.signing_certificate_pem.present?
- xml.KeyDescriptor use: "signing" do
- xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
- xml.X509Data do
- xml.X509Certificate @configuration.stripped_signing_certificate
- end
- end
- end
- end
- if @configuration.encryption_certificate_pem.present?
- xml.KeyDescriptor use: "encryption" do
- xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
- xml.X509Data do
- xml.X509Certificate @configuration.stripped_encryption_certificate
- end
- end
- end
- end
- logout_urls.each do |item|
- xml.SingleLogoutService Binding: item[:binding], Location: item[:location]
- end
- name_id_formats.each do |format|
- xml.NameIDFormat format
- end
- single_sign_on_urls.each do |item|
- xml.SingleSignOnService Binding: item[:binding], Location: item[:location]
- end
- attributes.each do |attribute|
- xml.tag! 'saml:Attribute', Name: attribute
- end
- end
- xml.Organization do
- xml.OrganizationName organization_name, 'xml:lang': "en"
- xml.OrganizationDisplayName organization_name, 'xml:lang': "en"
- xml.OrganizationURL organization_url, 'xml:lang': "en"
- end
- xml.ContactPerson contactType: "technical" do
- xml.Company "mailto:#{contact_email}"
- end
- end
- end
- end
-
- def build
- IdentityProviderMetadata.new(to_xml)
- end
-
- private
-
- def entity_descriptor_options
- {
- 'xmlns': Namespaces::METADATA,
- 'xmlns:ds': Namespaces::XMLDSIG,
- 'xmlns:saml': Namespaces::ASSERTION,
- ID: "_#{id}",
- entityID: entity_id,
- }
- end
-
- def idp_sso_descriptor_options
- {
- WantAuthnRequestsSigned: want_authn_requests_signed,
- protocolSupportEnumeration: Namespaces::PROTOCOL,
- }
- end
- end
end
end
end
spec/saml/builders/identity_provider_metadata_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+RSpec.describe Saml::Kit::IdentityProviderMetadata::Builder do
+ subject { described_class.new }
+ let(:email) { FFaker::Internet.email }
+ let(:org_name) { FFaker::Movie.title }
+ let(:url) { "https://#{FFaker::Internet.domain_name}" }
+ let(:entity_id) { FFaker::Movie.title }
+
+ it 'builds a proper metadata' do
+ subject.contact_email = email
+ subject.entity_id = entity_id
+ subject.organization_name = org_name
+ subject.organization_url = url
+ subject.name_id_formats = [
+ Saml::Kit::Namespaces::PERSISTENT,
+ Saml::Kit::Namespaces::TRANSIENT,
+ Saml::Kit::Namespaces::EMAIL_ADDRESS,
+ ]
+ subject.add_single_sign_on_service("https://www.example.com/login", binding: :http_redirect)
+ subject.add_single_logout_service("https://www.example.com/logout", binding: :http_post)
+ subject.attributes << "id"
+
+ result = Hash.from_xml(subject.build.to_xml)
+
+ expect(result['EntityDescriptor']['ID']).to be_present
+ expect(result['EntityDescriptor']['entityID']).to eql(entity_id)
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['protocolSupportEnumeration']).to eql(Saml::Kit::Namespaces::PROTOCOL)
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['WantAuthnRequestsSigned']).to eql('true')
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['NameIDFormat']).to match_array([
+ Saml::Kit::Namespaces::PERSISTENT,
+ Saml::Kit::Namespaces::TRANSIENT,
+ Saml::Kit::Namespaces::EMAIL_ADDRESS,
+ ])
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService']['Binding']).to eql(Saml::Kit::Bindings::HTTP_REDIRECT)
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService']['Location']).to eql("https://www.example.com/login")
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleLogoutService']['Binding']).to eql(Saml::Kit::Bindings::HTTP_POST)
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleLogoutService']['Location']).to eql("https://www.example.com/logout")
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['Attribute']['Name']).to eql("id")
+ certificates = result['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor'].map { |x| x['KeyInfo']['X509Data']['X509Certificate'] }
+ expect(certificates).to match_array([
+ Saml::Kit.configuration.stripped_signing_certificate,
+ Saml::Kit.configuration.stripped_encryption_certificate,
+ ])
+ expect(result['EntityDescriptor']['Organization']['OrganizationName']).to eql(org_name)
+ expect(result['EntityDescriptor']['Organization']['OrganizationDisplayName']).to eql(org_name)
+ expect(result['EntityDescriptor']['Organization']['OrganizationURL']).to eql(url)
+ expect(result['EntityDescriptor']['ContactPerson']['contactType']).to eql("technical")
+ expect(result['EntityDescriptor']['ContactPerson']['Company']).to eql("mailto:#{email}")
+ end
+end
spec/saml/identity_provider_metadata_spec.rb
@@ -187,54 +187,4 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
expect(subject.single_logout_service_for(binding: :soap)).to be_nil
end
end
-
- describe described_class::Builder do
- subject { described_class.new }
- let(:email) { FFaker::Internet.email }
- let(:org_name) { FFaker::Movie.title }
- let(:url) { "https://#{FFaker::Internet.domain_name}" }
- let(:entity_id) { FFaker::Movie.title }
-
- it 'builds a proper metadata' do
- subject.contact_email = email
- subject.entity_id = entity_id
- subject.organization_name = org_name
- subject.organization_url = url
- subject.name_id_formats = [
- Saml::Kit::Namespaces::PERSISTENT,
- Saml::Kit::Namespaces::TRANSIENT,
- Saml::Kit::Namespaces::EMAIL_ADDRESS,
- ]
- subject.add_single_sign_on_service("https://www.example.com/login", binding: :http_redirect)
- subject.add_single_logout_service("https://www.example.com/logout", binding: :http_post)
- subject.attributes << "id"
-
- result = Hash.from_xml(subject.build.to_xml)
-
- expect(result['EntityDescriptor']['ID']).to be_present
- expect(result['EntityDescriptor']['entityID']).to eql(entity_id)
- expect(result['EntityDescriptor']['IDPSSODescriptor']['protocolSupportEnumeration']).to eql(Saml::Kit::Namespaces::PROTOCOL)
- expect(result['EntityDescriptor']['IDPSSODescriptor']['WantAuthnRequestsSigned']).to eql('true')
- expect(result['EntityDescriptor']['IDPSSODescriptor']['NameIDFormat']).to match_array([
- Saml::Kit::Namespaces::PERSISTENT,
- Saml::Kit::Namespaces::TRANSIENT,
- Saml::Kit::Namespaces::EMAIL_ADDRESS,
- ])
- expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService']['Binding']).to eql(Saml::Kit::Bindings::HTTP_REDIRECT)
- expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService']['Location']).to eql("https://www.example.com/login")
- expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleLogoutService']['Binding']).to eql(Saml::Kit::Bindings::HTTP_POST)
- expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleLogoutService']['Location']).to eql("https://www.example.com/logout")
- expect(result['EntityDescriptor']['IDPSSODescriptor']['Attribute']['Name']).to eql("id")
- certificates = result['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor'].map { |x| x['KeyInfo']['X509Data']['X509Certificate'] }
- expect(certificates).to match_array([
- Saml::Kit.configuration.stripped_signing_certificate,
- Saml::Kit.configuration.stripped_encryption_certificate,
- ])
- expect(result['EntityDescriptor']['Organization']['OrganizationName']).to eql(org_name)
- expect(result['EntityDescriptor']['Organization']['OrganizationDisplayName']).to eql(org_name)
- expect(result['EntityDescriptor']['Organization']['OrganizationURL']).to eql(url)
- expect(result['EntityDescriptor']['ContactPerson']['contactType']).to eql("technical")
- expect(result['EntityDescriptor']['ContactPerson']['Company']).to eql("mailto:#{email}")
- end
- end
end