mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
Fix fetching of SAML metadata for large aggregate endpoints (#23531)
* Fix fetching of SAML metadata for large aggregate endpoints https://community.openproject.org/work_packages/OP-19420 * Use XML pull parser to avoid text parsing
This commit is contained in:
@@ -47,6 +47,8 @@ module Saml
|
||||
url: { allow_blank: true, allow_nil: true, schemes: %w[http https] },
|
||||
if: -> { model.metadata_url_changed? }
|
||||
|
||||
attribute :idp_entity_id
|
||||
|
||||
attribute :idp_sso_service_url
|
||||
validates :idp_sso_service_url,
|
||||
url: { schemes: %w[http https] },
|
||||
|
||||
@@ -40,6 +40,14 @@ module Saml
|
||||
caption: I18n.t("saml.instructions.metadata_url"),
|
||||
input_width: :xlarge
|
||||
)
|
||||
f.text_field(
|
||||
name: :idp_entity_id,
|
||||
label: I18n.t("activerecord.attributes.saml/provider.idp_entity_id"),
|
||||
required: false,
|
||||
disabled: provider.seeded_from_env?,
|
||||
caption: I18n.t("saml.instructions.idp_entity_id"),
|
||||
input_width: :xlarge
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,6 +42,14 @@ module Saml
|
||||
rows: 10,
|
||||
input_width: :medium
|
||||
)
|
||||
f.text_field(
|
||||
name: :idp_entity_id,
|
||||
label: I18n.t("activerecord.attributes.saml/provider.idp_entity_id"),
|
||||
required: false,
|
||||
disabled: provider.seeded_from_env?,
|
||||
caption: I18n.t("saml.instructions.idp_entity_id"),
|
||||
input_width: :xlarge
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,6 +11,7 @@ module Saml
|
||||
store_attribute :options, :metadata_xml, :string
|
||||
store_attribute :options, :last_metadata_update, :datetime
|
||||
|
||||
store_attribute :options, :idp_entity_id, :string
|
||||
store_attribute :options, :idp_sso_service_url, :string
|
||||
store_attribute :options, :idp_slo_service_url, :string
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Saml
|
||||
# Prepares SAML metadata XML for parsing by ruby-saml.
|
||||
#
|
||||
# Federation aggregates MAY contain thousands of individual entities.
|
||||
# Using ruby-saml directly would load the full document into REXML, which is extremely slow.
|
||||
# This class streams the XML and tries to extract the matching single EntityDescriptor when we can.
|
||||
class MetadataDocument
|
||||
class MetadataTooLargeError < StandardError; end
|
||||
|
||||
class FederationMetadataError < StandardError; end
|
||||
|
||||
MAX_SIZE = 150.megabytes
|
||||
|
||||
def self.prepare(source, entity_id: nil)
|
||||
new(source, entity_id:).prepare
|
||||
end
|
||||
|
||||
def initialize(source, entity_id: nil)
|
||||
@source = source
|
||||
@entity_id = entity_id.presence
|
||||
end
|
||||
|
||||
def prepare
|
||||
if aggregate?
|
||||
read_entity_fragment!
|
||||
else
|
||||
read_all
|
||||
end
|
||||
end
|
||||
|
||||
def read_entity_fragment!
|
||||
fragment = extract_entity_fragment
|
||||
if fragment.nil?
|
||||
message =
|
||||
if @entity_id
|
||||
"Entity '#{@entity_id}' not found in federation aggregate"
|
||||
else
|
||||
"No identity provider found in federation aggregate"
|
||||
end
|
||||
raise FederationMetadataError, message
|
||||
end
|
||||
|
||||
fragment
|
||||
end
|
||||
|
||||
# Decide whether the document is a federation aggregate by inspecting its root element.
|
||||
# Using +Nokogiri::XML::Reader+, we only advance to the root element and stop based on it.
|
||||
def aggregate?
|
||||
with_reader_io do |io|
|
||||
Nokogiri::XML::Reader(io).each do |node|
|
||||
next unless node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
|
||||
|
||||
return node.local_name == "EntitiesDescriptor"
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def extract_entity_fragment
|
||||
if @entity_id
|
||||
find_entity_by_id
|
||||
else
|
||||
find_first_idp_entity
|
||||
end
|
||||
end
|
||||
|
||||
# We try to prevent calling outer_xml on all entities when looking.
|
||||
# Instead, we can only look at entityID attribute until the target is found,
|
||||
# and then call outer_xml only on that fragment.
|
||||
def find_entity_by_id
|
||||
with_reader_io do |io|
|
||||
Nokogiri::XML::Reader(io).each do |node|
|
||||
next unless entity_descriptor_element?(node)
|
||||
next unless node.attribute("entityID") == @entity_id
|
||||
|
||||
return node.outer_xml
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def find_first_idp_entity
|
||||
with_reader_io do |io|
|
||||
Nokogiri::XML::Reader(io).each do |node|
|
||||
next unless entity_descriptor_element?(node)
|
||||
|
||||
fragment = node.outer_xml
|
||||
return fragment if idp_descriptor_fragment?(fragment)
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def idp_descriptor_fragment?(fragment)
|
||||
Nokogiri::XML.fragment(fragment).at_xpath(".//*[local-name()='IDPSSODescriptor']").present?
|
||||
end
|
||||
|
||||
def entity_descriptor_element?(node)
|
||||
node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT && node.local_name == "EntityDescriptor"
|
||||
end
|
||||
|
||||
def read_all
|
||||
return @source if @source.is_a?(String)
|
||||
|
||||
with_reader_io(&:read)
|
||||
end
|
||||
|
||||
def with_reader_io(&)
|
||||
if @source.is_a?(String)
|
||||
StringIO.open(@source, &)
|
||||
else
|
||||
@source.rewind
|
||||
yield @source
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,69 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Saml
|
||||
class MetadataFetcher
|
||||
include ActionView::Helpers::NumberHelper
|
||||
|
||||
def self.fetch(url, &)
|
||||
new(url).fetch(&)
|
||||
end
|
||||
|
||||
def initialize(url)
|
||||
@url = url
|
||||
end
|
||||
|
||||
def fetch
|
||||
Tempfile.create("saml-metadata") do |file|
|
||||
file.binmode
|
||||
|
||||
OpenProject::SsrfProtection.get(@url) do |response|
|
||||
unless response.is_a?(Net::HTTPSuccess)
|
||||
raise OneLogin::RubySaml::HttpError,
|
||||
"Failed to fetch idp metadata: #{response.code}: #{response.message}"
|
||||
end
|
||||
|
||||
bytes_written = 0
|
||||
response.read_body do |chunk|
|
||||
file.write(chunk)
|
||||
bytes_written += chunk.bytesize
|
||||
if bytes_written > MetadataDocument::MAX_SIZE
|
||||
raise MetadataDocument::MetadataTooLargeError,
|
||||
"Metadata exceeds max size of #{number_to_human_size(MetadataDocument::MAX_SIZE, precision: 2)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
file.rewind
|
||||
yield file
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -39,8 +39,14 @@ module Saml
|
||||
@provider = provider
|
||||
end
|
||||
|
||||
def call
|
||||
def call # rubocop:disable Metrics/AbcSize
|
||||
apply_metadata(merge_certificates(fetch_metadata))
|
||||
rescue MetadataDocument::FederationMetadataError => e
|
||||
OpenProject.logger.error(e)
|
||||
ServiceResult.failure(result: provider, message: I18n.t("saml.metadata_parser.federation_metadata"))
|
||||
rescue MetadataDocument::MetadataTooLargeError => e
|
||||
OpenProject.logger.error(e)
|
||||
ServiceResult.failure(result: provider, message: I18n.t("saml.metadata_parser.metadata_too_large"))
|
||||
rescue StandardError => e
|
||||
OpenProject.logger.error(e)
|
||||
ServiceResult.failure(result: provider,
|
||||
@@ -69,12 +75,16 @@ module Saml
|
||||
end
|
||||
|
||||
def parse_xml
|
||||
parser_instance.parse_to_hash(provider.metadata_xml)
|
||||
xml = MetadataDocument.prepare(provider.metadata_xml, entity_id: provider.idp_entity_id)
|
||||
parser_instance.parse_to_hash(xml)
|
||||
end
|
||||
|
||||
def parse_url
|
||||
validate_metadata_url_host!
|
||||
parser_instance.parse_remote_to_hash(provider.metadata_url)
|
||||
MetadataFetcher.fetch(provider.metadata_url) do |file|
|
||||
xml = MetadataDocument.prepare(file, entity_id: provider.idp_entity_id)
|
||||
parser_instance.parse_to_hash(xml)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_metadata_url_host!
|
||||
|
||||
@@ -12,6 +12,7 @@ en:
|
||||
sp_entity_id: Service entity ID
|
||||
metadata_url: Identity provider metadata URL
|
||||
name_identifier_format: Name identifier format
|
||||
idp_entity_id: Identity provider entity ID
|
||||
idp_sso_service_url: Identity provider login endpoint
|
||||
idp_slo_service_url: Identity provider logout endpoint
|
||||
idp_cert: Public certificate of identity provider
|
||||
@@ -43,6 +44,10 @@ en:
|
||||
success: "Successfully updated the configuration using the identity provider metadata."
|
||||
invalid_url: "Provided metadata URL is invalid. Provide a HTTP(s) URL."
|
||||
error: "Failed to retrieve the identity provider metadata: %{error}"
|
||||
federation_metadata: >
|
||||
The metadata URL points to a federation aggregate (many identity providers).
|
||||
Use your institution's direct metadata URL, or enter your institution's IdP entity ID in the metadata form and try again.
|
||||
metadata_too_large: "The metadata file exceeds the maximum allowed size."
|
||||
providers:
|
||||
label_empty_title: "No SAML providers configured yet."
|
||||
label_empty_description: "Add a provider to see them here."
|
||||
@@ -107,6 +112,9 @@ en:
|
||||
Your identity provider does not have a metadata endpoint or XML download option. You can configure it manually.
|
||||
metadata_url: >
|
||||
Your identity provider provides a metadata URL.
|
||||
idp_entity_id: >
|
||||
Optional: Useful when the metadata URL points to a federation aggregate with a lot of entries.
|
||||
Enter the entity ID of your institution's identity provider. Leave blank for single-entity metadata URLs.
|
||||
metadata_xml: >
|
||||
Your identity provider provides a metadata XML download.
|
||||
limit_self_registration: >
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<md:EntitiesDescriptor
|
||||
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
|
||||
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
|
||||
xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui"
|
||||
xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi"
|
||||
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
||||
xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute"
|
||||
Name="test-federation">
|
||||
<md:EntityDescriptor entityID="https://sp.state-university.edu/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">State University Portal</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Student and staff portal of State University</mdui:Description>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDKzCCAhOgAwIBAgIUNKP1WT7mAMRllZ3z8EDR2to1VNYwDQYJKoZIhvcNAQELBQAwJTEjMCEG
|
||||
A1UEAwwaaWRwLmV4YW1wbGUtdW5pdmVyc2l0eS5lZHUwHhcNMjYwNjAzMDg1NDI3WhcNMzYwNTMx
|
||||
MDg1NDI3WjAlMSMwIQYDVQQDDBppZHAuZXhhbXBsZS11bml2ZXJzaXR5LmVkdTCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAK+dgrVLuW+JCM2ST/SfA1J8XX3aCgtuU18Z1Xb8PcmMjQCJ
|
||||
Ow0PDIApqp/JJAyt7KDiv8cgJgAmPMGbVQpcmMcOInBu+AvTsndagVqV7V3ePLwN/WOm+NPVoB2g
|
||||
EEYGhF32gwZSQ0SHtJphxy4KoJv8CspVWRTviFU/pi1t8HsWJBLW6U6Jb7eLySM/G//6AFWFULdH
|
||||
GImkAk/9BfT7iCINYHsOW0MO237UKw90qShxtFCB/fqPRC6eldC2kFkod9eIw9x7cMuH74QGVsCd
|
||||
XAv+HUUtd6ov8Vn0xwaDiDxneXgKEBMwdVl97B+s9egUuif2TuMSYF09Qx7KREyayC0CAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFHh0ON9CYmfpcEQYlxixtd6kkmHVMB8GA1UdIwQYMBaAFHh0ON9CYmfpcEQY
|
||||
lxixtd6kkmHVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABSLwFVGf8L9+alT
|
||||
RU3n3D+vyUOvb5zb3hMER3WN0p323nQyeZ7WVSfIy3vsD2PcdsDinYpM9NV9P5zU+11PgAMRwqGv
|
||||
UnQLbklJ3d/5ciwdCVPUk+/c8pVwOnrCa5D6m1C8Or4Pnoxihz7sdmGoaGXdlrDhcwzosKx/AcT1
|
||||
aJNor+3SzkXJLzNfrYypBeUS8XzlzH3lTY+J1aYrfzXNK06XPCMlckKVL4nFVe0yDrSUk9DiLojy
|
||||
b90TaOSCqAGzoecoV8MOCxef6EvFgHmPpq8oMycWal4Ud2zdugUOtnNWxUVvWS15L7O7VG1eley/z
|
||||
UrWMUi2pWJ1Gk1NAFs8/0A=</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:AssertionConsumerService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://sp.state-university.edu/Shibboleth.sso/SAML2/POST"
|
||||
index="1"/>
|
||||
</md:SPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">State University</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">State University</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.state-university.edu</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Alex</md:GivenName>
|
||||
<md:SurName>Smith</md:SurName>
|
||||
<md:EmailAddress>mailto:asmith@state-university.edu</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
<md:EntityDescriptor entityID="https://sp.tech-institute.ac.uk/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">Tech Institute Library</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Electronic resources portal for Tech Institute staff</mdui:Description>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDKzCCAhOgAwIBAgIUNKP1WT7mAMRllZ3z8EDR2to1VNYwDQYJKoZIhvcNAQELBQAwJTEjMCEG
|
||||
A1UEAwwaaWRwLmV4YW1wbGUtdW5pdmVyc2l0eS5lZHUwHhcNMjYwNjAzMDg1NDI3WhcNMzYwNTMx
|
||||
MDg1NDI3WjAlMSMwIQYDVQQDDBppZHAuZXhhbXBsZS11bml2ZXJzaXR5LmVkdTCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAK+dgrVLuW+JCM2ST/SfA1J8XX3aCgtuU18Z1Xb8PcmMjQCJ
|
||||
Ow0PDIApqp/JJAyt7KDiv8cgJgAmPMGbVQpcmMcOInBu+AvTsndagVqV7V3ePLwN/WOm+NPVoB2g
|
||||
EEYGhF32gwZSQ0SHtJphxy4KoJv8CspVWRTviFU/pi1t8HsWJBLW6U6Jb7eLySM/G//6AFWFULdH
|
||||
GImkAk/9BfT7iCINYHsOW0MO237UKw90qShxtFCB/fqPRC6eldC2kFkod9eIw9x7cMuH74QGVsCd
|
||||
XAv+HUUtd6ov8Vn0xwaDiDxneXgKEBMwdVl97B+s9egUuif2TuMSYF09Qx7KREyayC0CAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFHh0ON9CYmfpcEQYlxixtd6kkmHVMB8GA1UdIwQYMBaAFHh0ON9CYmfpcEQY
|
||||
lxixtd6kkmHVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABSLwFVGf8L9+alT
|
||||
RU3n3D+vyUOvb5zb3hMER3WN0p323nQyeZ7WVSfIy3vsD2PcdsDinYpM9NV9P5zU+11PgAMRwqGv
|
||||
UnQLbklJ3d/5ciwdCVPUk+/c8pVwOnrCa5D6m1C8Or4Pnoxihz7sdmGoaGXdlrDhcwzosKx/AcT1
|
||||
aJNor+3SzkXJLzNfrYypBeUS8XzlzH3lTY+J1aYrfzXNK06XPCMlckKVL4nFVe0yDrSUk9DiLojy
|
||||
b90TaOSCqAGzoecoV8MOCxef6EvFgHmPpq8oMycWal4Ud2zdugUOtnNWxUVvWS15L7O7VG1eley/z
|
||||
UrWMUi2pWJ1Gk1NAFs8/0A=</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:AssertionConsumerService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://sp.tech-institute.ac.uk/Shibboleth.sso/SAML2/POST"
|
||||
index="1"/>
|
||||
</md:SPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">Tech Institute</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">Tech Institute</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.tech-institute.ac.uk</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Jamie</md:GivenName>
|
||||
<md:SurName>Taylor</md:SurName>
|
||||
<md:EmailAddress>mailto:jtaylor@tech-institute.ac.uk</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
<md:EntityDescriptor entityID="https://sp.research-center.de/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">Research Center Data Portal</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Scientific data access portal</mdui:Description>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDKzCCAhOgAwIBAgIUNKP1WT7mAMRllZ3z8EDR2to1VNYwDQYJKoZIhvcNAQELBQAwJTEjMCEG
|
||||
A1UEAwwaaWRwLmV4YW1wbGUtdW5pdmVyc2l0eS5lZHUwHhcNMjYwNjAzMDg1NDI3WhcNMzYwNTMx
|
||||
MDg1NDI3WjAlMSMwIQYDVQQDDBppZHAuZXhhbXBsZS11bml2ZXJzaXR5LmVkdTCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAK+dgrVLuW+JCM2ST/SfA1J8XX3aCgtuU18Z1Xb8PcmMjQCJ
|
||||
Ow0PDIApqp/JJAyt7KDiv8cgJgAmPMGbVQpcmMcOInBu+AvTsndagVqV7V3ePLwN/WOm+NPVoB2g
|
||||
EEYGhF32gwZSQ0SHtJphxy4KoJv8CspVWRTviFU/pi1t8HsWJBLW6U6Jb7eLySM/G//6AFWFULdH
|
||||
GImkAk/9BfT7iCINYHsOW0MO237UKw90qShxtFCB/fqPRC6eldC2kFkod9eIw9x7cMuH74QGVsCd
|
||||
XAv+HUUtd6ov8Vn0xwaDiDxneXgKEBMwdVl97B+s9egUuif2TuMSYF09Qx7KREyayC0CAwEAAaNT
|
||||
MFEwHQYDVR0OBBYEFHh0ON9CYmfpcEQYlxixtd6kkmHVMB8GA1UdIwQYMBaAFHh0ON9CYmfpcEQY
|
||||
lxixtd6kkmHVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABSLwFVGf8L9+alT
|
||||
RU3n3D+vyUOvb5zb3hMER3WN0p323nQyeZ7WVSfIy3vsD2PcdsDinYpM9NV9P5zU+11PgAMRwqGv
|
||||
UnQLbklJ3d/5ciwdCVPUk+/c8pVwOnrCa5D6m1C8Or4Pnoxihz7sdmGoaGXdlrDhcwzosKx/AcT1
|
||||
aJNor+3SzkXJLzNfrYypBeUS8XzlzH3lTY+J1aYrfzXNK06XPCMlckKVL4nFVe0yDrSUk9DiLojy
|
||||
b90TaOSCqAGzoecoV8MOCxef6EvFgHmPpq8oMycWal4Ud2zdugUOtnNWxUVvWS15L7O7VG1eley/z
|
||||
UrWMUi2pWJ1Gk1NAFs8/0A=</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:AssertionConsumerService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://sp.research-center.de/Shibboleth.sso/SAML2/POST"
|
||||
index="1"/>
|
||||
</md:SPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">Research Center</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">Research Center</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.research-center.de</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Maria</md:GivenName>
|
||||
<md:SurName>Weber</md:SurName>
|
||||
<md:EmailAddress>mailto:mweber@research-center.de</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
<!-- ==================== IdP entities ==================== -->
|
||||
|
||||
<md:EntityDescriptor entityID="https://idp.state-university.edu/idp/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">State University</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Identity provider of State University</mdui:Description>
|
||||
<mdui:InformationURL xml:lang="en">https://www.state-university.edu</mdui:InformationURL>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDJzCCAg+gAwIBAgIULPAnn8haVhQcUbxjrZLjtbFX5RkwDQYJKoZIhvcNAQELBQAwIzEhMB8G
|
||||
A1UEAwwYaWRwLnN0YXRlLXVuaXZlcnNpdHkuZWR1MB4XDTI2MDYwMzA4NTQ0OVoXDTM2MDUzMTA4
|
||||
NTQ0OVowIzEhMB8GA1UEAwwYaWRwLnN0YXRlLXVuaXZlcnNpdHkuZWR1MIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAwo21vefLRM/2iK6LO4Sbl++0h+zrLuSSusY/0Wu3QjPAGklaqzQ0j
|
||||
Dc2jbY5bXei4ebWuGxT5PCqPOFIaTQM8uJ5q7uVAo06ab6/uSfwjDJTNE7jokhMeilNh4GuoWTsb
|
||||
CyGMDUbSdfTNTDCC/ELoWlTCErce+TuIZulG8Jzmmm3AKTmMjOW+Ch3HMLoKCmEyniKs7m0eB7Az
|
||||
298bFCFKp0dpqkfre5U5WTYeFe39RBbZfDPl0bN0UxF1T7ITOf6tkryXPJXfQAnXDiCnB22A936M
|
||||
5ou1XFTozkE8RBbgOjq34zBbM0V69rPnhh0yqFDIVUVtULcgyJQEIB5qpigDQIDAQABo1MwUTAdBg
|
||||
NVHQ4EFgQUQ4UIhO5Q3RmegmL27mKP0j5QJQ4wHwYDVR0jBBgwFoAUQ4UIhO5Q3RmegmL27mKP0j
|
||||
5QJQ4wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEALUR5WnK0mbu2lPO6CXd7LTs
|
||||
IcRdEq/qXRQC+KqofuS5dyZ0N2ip0zD50tG6y8YjWQHERQ89+ZEKv5VmD9+k4PnZpNfVjfmyeivq
|
||||
bWohIn/0iNAUNmY/bam0qbz8SCiLPLVrKvu9BAGWcoV7UX9zf+qe+NNT8z1bFVR3+WcnnO/AEWyu
|
||||
UVab0ud6HYp5xc36Jj3e98T50h5OaXpQpwfyuM7/p4WX3Ri5FRa0tNxlAy685cuL6B5zrbUOoc+Q
|
||||
sc3FqNtGFM/TExrW9VY/kRQVDpuhqv/eUO7RfQJmv1FBhP+XMdXUudJ6aNFswI0P1UO/H9YGm93U
|
||||
CXnNW8NGo/MwFSg==</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:SingleLogoutService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.state-university.edu/idp/profile/SAML2/Redirect/SLO"/>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.state-university.edu/idp/profile/SAML2/Redirect/SSO"/>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://idp.state-university.edu/idp/profile/SAML2/POST/SSO"/>
|
||||
</md:IDPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">State University</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">State University</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.state-university.edu</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Alex</md:GivenName>
|
||||
<md:SurName>Smith</md:SurName>
|
||||
<md:EmailAddress>mailto:asmith@state-university.edu</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
<md:EntityDescriptor entityID="https://idp.tech-institute.ac.uk/idp/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">Tech Institute</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Identity provider of Tech Institute</mdui:Description>
|
||||
<mdui:InformationURL xml:lang="en">https://www.tech-institute.ac.uk</mdui:InformationURL>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDJzCCAg+gAwIBAgIUFozhkEI22FNzfgPfPg6tXhOCsLMwDQYJKoZIhvcNAQELBQAwIzEhMB8G
|
||||
A1UEAwwYaWRwLnRlY2gtaW5zdGl0dXRlLmFjLnVrMB4XDTI2MDYwMzA4NTQ0OVoXDTM2MDUzMTA4
|
||||
NTQ0OVowIzEhMB8GA1UEAwwYaWRwLnRlY2gtaW5zdGl0dXRlLmFjLnVrMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAodVdylnMKJ5d3p7vZqX4za/12IJVI7/Xsyi7S1UxfB52vktX9EZo
|
||||
IxqO9GLMe9lIrHFOB8jU1I7BdYp8r0E4mo44YYikncOMKNaOuHF5J1WaJOUZd807jriGO9agZor9
|
||||
AmABRpl3w/WYVL9OZPj1mHngQPWaVcosM3OkxXwdULPdcxfe3VATHcNWi7uoLZsB0hpBwua47ldS
|
||||
wThmZkVNjdjlD0BRiUCSynFtSY2vGxHz+D/aBvYhrGlBX4uTPCOxqybyC3dfadD9ZlvLfY0d1Yic
|
||||
ZvNEybP8bPcu8xUwnsyL6bBsdat7/XXbawOsxEXxSR9wcv42ZfgKmKyTyUdpLQIDAQABo1MwUTAd
|
||||
BgNVHQ4EFgQUDVmR5rn9fYj2XkwffcZAwCWKvfowHwYDVR0jBBgwFoAUDVmR5rn9fYj2XkwffcZA
|
||||
wCWKvfowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAnVbAE4SsEYhodobnZEWGu
|
||||
z/747XH/m7DM9KM4lvKq6QOd/C/aJ7Lp9nwfl1gXIHdwdYozlOpak2+zfVFFbepvDOldldpScJzZ
|
||||
sC+80PTta+h91OTug6Q+viRJV/OzQPozLJ6jz5Tox8dYn7T2XIfmM49jX+tAR861QopVaHLmZ3Lg
|
||||
EHzsk+aIV6I6yyJfBmpy4+tO5OhKv3UHLCHmo7NPVhiX+pxe3+XCghdRtKMFCB9gwqJxYoybHb+a
|
||||
NrbgZmhp6hjzd9tsFQDMSdkCSTHWCaqua5Hi4EfMIR75SKxUZvrCkTe4FOa+rG5bq26vdeKBZUCs
|
||||
sd+OCMN3dWtH446Lf7Gw==</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:SingleLogoutService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.tech-institute.ac.uk/idp/profile/SAML2/Redirect/SLO"/>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.tech-institute.ac.uk/idp/profile/SAML2/Redirect/SSO"/>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://idp.tech-institute.ac.uk/idp/profile/SAML2/POST/SSO"/>
|
||||
</md:IDPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">Tech Institute</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">Tech Institute</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.tech-institute.ac.uk</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Jamie</md:GivenName>
|
||||
<md:SurName>Taylor</md:SurName>
|
||||
<md:EmailAddress>mailto:jtaylor@tech-institute.ac.uk</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
<md:EntityDescriptor entityID="https://idp.research-center.de/idp/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">Research Center</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Identity provider of Research Center</mdui:Description>
|
||||
<mdui:InformationURL xml:lang="en">https://www.research-center.de</mdui:InformationURL>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDIzCCAgugAwIBAgIUcxlF9USQY3nQvvO8uqXJL7C8/XgwDQYJKoZIhvcNAQELBQAwITEfMB0G
|
||||
A1UEAwwWaWRwLnJlc2VhcmNoLWNlbnRlci5kZTAeFw0yNjA2MDMwODU0NDlaFw0zNjA1MzEwODU0
|
||||
NDlaMCExHzAdBgNVBAMMFmlkcC5yZXNlYXJjaC1jZW50ZXIuZGUwggEiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBDwAwggEKAoIBAQDPxGQuYQjgdNedu3dgelQQ5t+1SxM4an4xQav4rXqG2ZtmEmDS3WDfy7Kc
|
||||
RKtSfW/6+zWmNUd6wQQnc+3VgnmOb+qRTSh9XCD3WFSrr/hG0HfrmzKtjo4nYK5gWLdXQwgwznu
|
||||
R40IOxsKEEtkp2UgkFLMAtGjJ15Kyu6J3eV8MIpB468G+mXXXhbLw7y8uB+cyCTWGsG1aa1ahmZS
|
||||
Rz7K9H1TafUSuarUis/+oXZO9+YJHNEi9iU4U6h9iTlqPkly146FefQlHsBys7T0Es46aIqiaCMC
|
||||
ygCDxhKK4Rwf0E67I9QMFbTW1y8LF5hKs42NBzcf46iAkwYgPzisbqZtLAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBSfqZUJOP+vllNKi2xk3Lbo8St4sDAfBgNVHSMEGDAWgBSfqZUJOP+vllNKi2xk3Lbo8St4
|
||||
sDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBAJPRIMKcogeICnsF2pfca25Gln
|
||||
5w13G95as+du3wx5ZVqQLH+JYLKcM6Uq7FVvWIrBwbOjCa9FEyUs1lATOtTkCZ3q05X/sw+sGMXI
|
||||
r8H/vkDhOPkwIlKRaSRJHCBGN3xk8lUxev6fwwlU3Ht0fQEiOAWlc9N231wDYFDIAXmJbN/tG3/l
|
||||
OfJUT1MXHdWe7QuJzmwLQ9OXogfdV2SskSQSqH9MKYcQ+qADc1lf0J0Or0GKSLvjz8YPLkwhXLGr
|
||||
NhM+VyjD50hrg0DkUtco/8RTnkC3FkAvI/6WjpSiejpjW8Muh3rRAzxnfA9FQV0S0YXmlb/isM/l
|
||||
Z6NiIkQ/8eB</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:SingleLogoutService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.research-center.de/idp/profile/SAML2/Redirect/SLO"/>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.research-center.de/idp/profile/SAML2/Redirect/SSO"/>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://idp.research-center.de/idp/profile/SAML2/POST/SSO"/>
|
||||
</md:IDPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">Research Center</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">Research Center</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.research-center.de</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Maria</md:GivenName>
|
||||
<md:SurName>Weber</md:SurName>
|
||||
<md:EmailAddress>mailto:mweber@research-center.de</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
<md:EntityDescriptor entityID="https://idp.national-lab.fr/idp/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">National Laboratory</mdui:DisplayName>
|
||||
<mdui:DisplayName xml:lang="fr">Laboratoire National</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Identity provider of National Laboratory</mdui:Description>
|
||||
<mdui:InformationURL xml:lang="en">https://www.national-lab.fr</mdui:InformationURL>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDHTCCAgWgAwIBAgIUUl2dXqMr4hJ6wf4fj/GOQlZAcpEwDQYJKoZIhvcNAQELBQAwHjEcMBoG
|
||||
A1UEAwwTaWRwLm5hdGlvbmFsLWxhYi5mcjAeFw0yNjA2MDMwODU0NDlaFw0zNjA1MzEwODU0NDla
|
||||
MB4xHDAaBgNVBAMME2lkcC5uYXRpb25hbC1sYWIuZnIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQDAlY882lrAlhuadc5xMT6U8ELf5zH7adGzGjtP76Kx9SLYewDASPXY7nXUx3aM2kqs
|
||||
o+MWX0iaVpnWYvV+LMFyH6Mg/12pZhRx8S/cQysYEV3loWVSi3lESkOK9ELR2BeWOrYyZtk3Pz3q
|
||||
AJ/BoSFegxe7OxC866m20LMKG9sDBB88i9svxmxXYxSR/HkAEfarSruk37aLOD++Iud+FBfJvRJR
|
||||
174MZj6gecIsGcXy2Zn41WLgjGl3/sWUK27SWoa9Up5vDTIeQ8lZ5ySbRT58M+eHCOxSVf/gFf7s
|
||||
49+v5i/9iDKDMo5Hy+MDbdovUaDo6KQmiPg6cfzqT52AT39lAgMBAAGjUzBRMB0GA1UdDgQWBBTj
|
||||
Gvmk9xkzVe57Cte2KOEnf3k2hzAfBgNVHSMEGDAWgBTjGvmk9xkzVe57Cte2KOEnf3k2hzAPBgNV
|
||||
HRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAMvHuuB2KGKl0n7d0MtJ2/fzKtJmJMMja2
|
||||
o1Mqj/rg2Nkq31wrFdXqayxypYDSXQgLoABkWYyZkWIhoWOnml2J9bUDJ8uYLulp4VbNZnAylAS5
|
||||
9hu/35ZEc9hmUrm9Q8JaevKdULneiIiR2R269oqf0QEJgF26ZzEEodH0oj7ZNOOuF2OXy+8R893Y
|
||||
DSnLHCEtW6uZWjEQTsfbGVcppvYYho6/K0/saO0IPb1/LZ8z1uB7CWbsn5KRnqR0AvT2+R5xlIxE
|
||||
k7uWFpPOkdfgfnJ9UbfN2tgDyiieyME3PZZ5sjGWs/StRfnt/z9FeB00T3chiF4ldtuIysmUFDLu
|
||||
3fm5</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:SingleLogoutService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.national-lab.fr/idp/profile/SAML2/Redirect/SLO"/>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.national-lab.fr/idp/profile/SAML2/Redirect/SSO"/>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://idp.national-lab.fr/idp/profile/SAML2/POST/SSO"/>
|
||||
</md:IDPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">National Laboratory</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">National Laboratory</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.national-lab.fr</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Sophie</md:GivenName>
|
||||
<md:SurName>Martin</md:SurName>
|
||||
<md:EmailAddress>mailto:smartin@national-lab.fr</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
<md:EntityDescriptor entityID="https://idp.polytechnic.edu.br/idp/shibboleth">
|
||||
<md:Extensions>
|
||||
<mdrpi:RegistrationInfo registrationAuthority="https://federation.example.org/"/>
|
||||
</md:Extensions>
|
||||
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:Extensions>
|
||||
<mdui:UIInfo>
|
||||
<mdui:DisplayName xml:lang="en">Polytechnic University</mdui:DisplayName>
|
||||
<mdui:DisplayName xml:lang="pt">Universidade Politécnica</mdui:DisplayName>
|
||||
<mdui:Description xml:lang="en">Identity provider of Polytechnic University</mdui:Description>
|
||||
<mdui:InformationURL xml:lang="en">https://www.polytechnic.edu.br</mdui:InformationURL>
|
||||
</mdui:UIInfo>
|
||||
</md:Extensions>
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDIzCCAgugAwIBAgIUcX6lAS/Bq/lth/N/EA1dj6b7aI4wDQYJKoZIhvcNAQELBQAwITEfMB0G
|
||||
A1UEAwwWaWRwLnBvbHl0ZWNobmljLmVkdS5icjAeFw0yNjA2MDMwODU0NDlaFw0zNjA1MzEwODU0
|
||||
NDlaMCExHzAdBgNVBAMMFmlkcC5wb2x5dGVjaG5pYy5lZHUuYnIwggEiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBDwAwggEKAoIBAQDgmBYTodZcgpqaimV8nFH/YH6I6Y2euIgEIIPTHVboHUXAgErOrSU1jzjF
|
||||
2S1UX7uHiyg00GSJyQPBPn2i73nTplDSyj0TzmcDdI2uWyY8kygozuGrsjVv7T+krTswlCYD+GhF
|
||||
09VK18Gk8VHX0DB/5GFFB03yORHSOi0MieJ5cIWNxDpSaj3UJyVnZdvA9jfxvJKIjVE3niNG82Gc
|
||||
Y70VglYRr5Gm814eDAYxhfqJNfSZxKowCmxrcTiKRN/E/hrEzFAYxXaCsyaO5WYs49+IOt2pNkJH
|
||||
t86ErHQEKjTF3sf10WsN9UzYz1zv74b6sqfT8GztSjmI7XcDN36ZooJBAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBTF0YvxRtWXlt/f1Y3//c6aX/gxxzAfBgNVHSMEGDAWgBTF0YvxRtWXlt/f1Y3//c6aX/gx
|
||||
xzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDVu6t9PvJ7ewKeJ05q7sFdNw9k
|
||||
MEjDdim/m3Y6j31YGjSdBXmKnaH898hliATkgv7EnzgFkCT45NtT8aX1pETDEl9kgxL/TjhdwdHK
|
||||
1q+Skou1NmJM+Zd7Zm8yvreA7Gj+YTiTL2iF4jeRTR+k04KZaQCLMgoxTQNgF/uxlitapX2+L+d
|
||||
IyTikGTkfINXNRjhvx2t3rUqJoxn/bl1qM6uS4A/R5aOne6xve5Kd+lyUCOxB/TZuHpDZgB6O1FT
|
||||
03HXTn4lmoCIiCPsjXhXqQOgTq+g8JPMUYtGAi4diNF+CWcD9Zv/1rdqCuGlk1O105HRIPcST5LF
|
||||
4MzCa1nJBoVPj</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:SingleLogoutService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.polytechnic.edu.br/idp/profile/SAML2/Redirect/SLO"/>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.polytechnic.edu.br/idp/profile/SAML2/Redirect/SSO"/>
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="https://idp.polytechnic.edu.br/idp/profile/SAML2/POST/SSO"/>
|
||||
</md:IDPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en">Polytechnic University</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en">Polytechnic University</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en">https://www.polytechnic.edu.br</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Carlos</md:GivenName>
|
||||
<md:SurName>Silva</md:SurName>
|
||||
<md:EmailAddress>mailto:csilva@polytechnic.edu.br</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
|
||||
</md:EntitiesDescriptor>
|
||||
@@ -0,0 +1,141 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Saml::MetadataDocument do
|
||||
# Fixture: 3 SPs then 5 IdPs — see spec/fixtures/federation_metadata.xml
|
||||
let(:federation_xml) { Rails.root.join("modules/auth_saml/spec/fixtures/federation_metadata.xml").read }
|
||||
|
||||
# Minimal single EntityDescriptor — not an aggregate, so prepare returns it unchanged
|
||||
let(:single_idp_xml) do
|
||||
<<~XML
|
||||
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
|
||||
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
|
||||
entityID="https://idp.example.com/idp/shibboleth">
|
||||
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:SingleSignOnService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="https://idp.example.com/idp/profile/SAML2/Redirect/SSO"/>
|
||||
</md:IDPSSODescriptor>
|
||||
</md:EntityDescriptor>
|
||||
XML
|
||||
end
|
||||
|
||||
# Entity IDs present in the fixture
|
||||
let(:first_idp_entity_id) { "https://idp.state-university.edu/idp/shibboleth" }
|
||||
let(:last_idp_entity_id) { "https://idp.polytechnic.edu.br/idp/shibboleth" }
|
||||
let(:sp_entity_id) { "https://sp.state-university.edu/shibboleth" }
|
||||
|
||||
describe ".prepare on a single-entity document" do
|
||||
it "returns the XML unchanged" do
|
||||
result = described_class.prepare(single_idp_xml)
|
||||
expect(result).to eq(single_idp_xml)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".prepare on a federation aggregate" do
|
||||
it "detects the aggregate" do
|
||||
expect(described_class.new(federation_xml).aggregate?).to be(true)
|
||||
end
|
||||
|
||||
context "without an entity_id" do
|
||||
it "returns the first IdP entity, skipping SP-only entries" do
|
||||
result = described_class.prepare(federation_xml)
|
||||
|
||||
expect(result).to include(first_idp_entity_id)
|
||||
expect(result).to include("IDPSSODescriptor")
|
||||
expect(result).not_to include("SPSSODescriptor")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a matching entity_id" do
|
||||
it "extracts the requested IdP" do
|
||||
result = described_class.prepare(federation_xml, entity_id: last_idp_entity_id)
|
||||
|
||||
expect(result).to include(last_idp_entity_id)
|
||||
expect(result).to include("IDPSSODescriptor")
|
||||
end
|
||||
|
||||
it "can also extract an SP entity by entity_id" do
|
||||
result = described_class.prepare(federation_xml, entity_id: sp_entity_id)
|
||||
|
||||
expect(result).to include(sp_entity_id)
|
||||
expect(result).to include("SPSSODescriptor")
|
||||
end
|
||||
end
|
||||
|
||||
context "with an entity_id not present in the aggregate" do
|
||||
it "raises FederationMetadataError with the missing entity_id in the message" do
|
||||
expect do
|
||||
described_class.prepare(federation_xml, entity_id: "https://missing.example.com/idp/shibboleth")
|
||||
end.to raise_error(described_class::FederationMetadataError, /missing\.example\.com/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the aggregate contains no IdPs and no entity_id is given" do
|
||||
let(:sp_only_aggregate) do
|
||||
<<~XML
|
||||
<md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
|
||||
<md:EntityDescriptor entityID="https://sp.example.com/shibboleth">
|
||||
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
|
||||
</md:EntityDescriptor>
|
||||
</md:EntitiesDescriptor>
|
||||
XML
|
||||
end
|
||||
|
||||
it "raises FederationMetadataError" do
|
||||
expect do
|
||||
described_class.prepare(sp_only_aggregate)
|
||||
end.to raise_error(described_class::FederationMetadataError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".prepare on an IO source (Tempfile)" do
|
||||
it "reads a single-entity file correctly" do
|
||||
Tempfile.create("spec-metadata") do |f|
|
||||
f.write(single_idp_xml)
|
||||
f.rewind
|
||||
expect(described_class.prepare(f)).to eq(single_idp_xml)
|
||||
end
|
||||
end
|
||||
|
||||
it "extracts the first IdP from a federation aggregate file" do
|
||||
Tempfile.create("spec-metadata") do |f|
|
||||
f.write(federation_xml)
|
||||
f.rewind
|
||||
result = described_class.prepare(f)
|
||||
expect(result).to include(first_idp_entity_id)
|
||||
expect(result).to include("IDPSSODescriptor")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,97 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Saml::MetadataFetcher do
|
||||
let(:url) { "https://example.com/metadata" }
|
||||
let(:response) { instance_double(Net::HTTPSuccess) }
|
||||
|
||||
before do
|
||||
allow(response).to receive(:is_a?).with(Net::HTTPSuccess).and_return(true)
|
||||
allow(OpenProject::SsrfProtection).to receive(:get).and_yield(response)
|
||||
end
|
||||
|
||||
describe ".fetch" do
|
||||
context "with a successful response" do
|
||||
before do
|
||||
allow(response).to receive(:read_body).and_yield("<xml/>")
|
||||
end
|
||||
|
||||
it "yields a file with the response body rewound to the start" do
|
||||
described_class.fetch(url) do |file|
|
||||
expect(file).to be_a(File)
|
||||
expect(file.pos).to eq(0)
|
||||
expect(file.read).to eq("<xml/>")
|
||||
end
|
||||
end
|
||||
|
||||
it "removes the tempfile after the block" do
|
||||
path = nil
|
||||
described_class.fetch(url) do |file|
|
||||
path = file.path
|
||||
expect(File.exist?(path)).to be(true)
|
||||
end
|
||||
expect(File.exist?(path)).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the response is not successful" do
|
||||
let(:response) { instance_double(Net::HTTPNotFound, code: "404", message: "Not Found") }
|
||||
|
||||
before do
|
||||
allow(response).to receive(:is_a?).with(Net::HTTPSuccess).and_return(false)
|
||||
allow(OpenProject::SsrfProtection).to receive(:get).and_yield(response)
|
||||
end
|
||||
|
||||
it "raises HttpError without yielding" do
|
||||
yielded = false
|
||||
expect do
|
||||
described_class.fetch(url) { yielded = true }
|
||||
end.to raise_error(OneLogin::RubySaml::HttpError, /404/)
|
||||
expect(yielded).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the response body exceeds MAX_SIZE" do
|
||||
before do
|
||||
allow(response).to receive(:read_body).and_yield("x" * (Saml::MetadataDocument::MAX_SIZE + 1))
|
||||
end
|
||||
|
||||
it "raises MetadataTooLargeError without yielding" do
|
||||
yielded = false
|
||||
expect do
|
||||
described_class.fetch(url) { yielded = true }
|
||||
end.to raise_error(Saml::MetadataDocument::MetadataTooLargeError)
|
||||
expect(yielded).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -231,22 +231,37 @@ RSpec.describe Saml::UpdateMetadataService do
|
||||
let(:metadata_url) { "https://example.com/metadata" }
|
||||
let(:provider) { Saml::Provider.new(metadata_url:) }
|
||||
let(:parser_instance) { instance_double(OneLogin::RubySaml::IdpMetadataParser) }
|
||||
let(:http_response) { instance_double(Net::HTTPSuccess) }
|
||||
|
||||
before do
|
||||
allow(OneLogin::RubySaml::IdpMetadataParser).to receive(:new).and_return(parser_instance)
|
||||
allow(parser_instance).to receive(:parse_remote_to_hash).and_return({})
|
||||
allow(parser_instance).to receive(:parse_to_hash).and_return({})
|
||||
allow(Saml::MetadataDocument).to receive(:prepare).and_return("<xml/>")
|
||||
allow(http_response).to receive(:is_a?).with(Net::HTTPSuccess).and_return(true)
|
||||
allow(http_response).to receive(:read_body).and_yield("<metadata/>")
|
||||
allow(OpenProject::SsrfProtection).to receive(:get)
|
||||
end
|
||||
|
||||
context "when the URL host resolves to a safe IP" do
|
||||
before do
|
||||
allow(OpenProject::SsrfProtection).to receive(:safe_ip?).with("example.com").and_return(IPAddr.new("93.184.216.34"))
|
||||
allow(OpenProject::SsrfProtection).to receive(:get).and_yield(http_response)
|
||||
end
|
||||
|
||||
it "checks the host and fetches metadata remotely" do
|
||||
it "checks the host, fetches metadata via MetadataFetcher, and cleans up the tempfile" do
|
||||
fetched_file = nil
|
||||
allow(Saml::MetadataDocument).to receive(:prepare) do |file, **|
|
||||
fetched_file = file
|
||||
"<xml/>"
|
||||
end
|
||||
|
||||
parse_metadata
|
||||
|
||||
expect(OpenProject::SsrfProtection).to have_received(:safe_ip?).with("example.com")
|
||||
expect(parser_instance).to have_received(:parse_remote_to_hash).with(metadata_url)
|
||||
expect(OpenProject::SsrfProtection).to have_received(:get).with(metadata_url)
|
||||
expect(Saml::MetadataDocument).to have_received(:prepare).with(instance_of(File), entity_id: nil)
|
||||
expect(parser_instance).to have_received(:parse_to_hash).with("<xml/>")
|
||||
expect(fetched_file).to be_closed
|
||||
end
|
||||
end
|
||||
|
||||
@@ -261,7 +276,7 @@ RSpec.describe Saml::UpdateMetadataService do
|
||||
expect(result).not_to be_success
|
||||
expect(result.message).to include("MetadataHostNotAllowedError")
|
||||
expect(OpenProject::SsrfProtection).to have_received(:safe_ip?).with("example.com")
|
||||
expect(parser_instance).not_to have_received(:parse_remote_to_hash)
|
||||
expect(OpenProject::SsrfProtection).not_to have_received(:get)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user