From 8b8a66f37afeb93c4d820b474d875652bd268310 Mon Sep 17 00:00:00 2001
From: jmf3658 <jfullmer@austin.utexas.edu>
Date: Wed, 18 Dec 2024 09:56:20 -0700
Subject: [PATCH 1/6] Add support for contactPerson and organization

---
 config/schema/samlauth.schema.yml      | 18 +++++++++++
 src/Form/SamlauthSamlConfigureForm.php | 42 ++++++++++++++++++++++++++
 src/SamlService.php                    | 42 +++++++++++++++++++++++++-
 3 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/config/schema/samlauth.schema.yml b/config/schema/samlauth.schema.yml
index 409dfa3..0ea43d1 100644
--- a/config/schema/samlauth.schema.yml
+++ b/config/schema/samlauth.schema.yml
@@ -196,3 +196,21 @@ samlauth.authentication:
     bypass_relay_state_check:
       type: boolean
       label: 'Bypass safety check for dynamic redirect URLs'
+    technical_givenName:
+      type: string
+      label: 'Technical given name'
+    technical_emailAddress:
+      type: string
+      label: 'Technical email address'
+    support_givenName:
+      type: string
+      label: 'Support given name'
+    support_emailAddress:
+      type: string
+      label: 'Support email address'
+    organization_name:
+      type: string
+      label: 'Organization name'
+    organization_url:
+      type: string
+      label: 'Organization URL'
diff --git a/src/Form/SamlauthSamlConfigureForm.php b/src/Form/SamlauthSamlConfigureForm.php
index 92dbf58..0549167 100644
--- a/src/Form/SamlauthSamlConfigureForm.php
+++ b/src/Form/SamlauthSamlConfigureForm.php
@@ -521,6 +521,42 @@ class SamlauthSamlConfigureForm extends ConfigFormBase {
         ],
       ],
     ];
+    $form['service_provider']['contact'] = [
+      '#type' => 'details',
+      '#open' => TRUE,
+      '#title' => $this->t('Contact information'),
+      '#description' => $this->t('It is recommended to supply technical and support contacts.'),
+    ];
+    $form['service_provider']['contact']['technical_givenName'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Technical contact given name'),
+      '#default_value' => $config->get('technical_givenName') ?? '',
+    ];
+    $form['service_provider']['contact']['technical_emailAddress'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Technical contact email'),
+      '#default_value' => $config->get('technical_emailAddress') ?? '',
+    ];
+    $form['service_provider']['contact']['support_givenName'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Support contact given name'),
+      '#default_value' => $config->get('support_givenName') ?? '',
+    ];
+    $form['service_provider']['contact']['support_emailAddress'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Support contact email'),
+      '#default_value' => $config->get('support_emailAddress') ?? '',
+    ];
+    $form['service_provider']['contact']['organization_name'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Organization Name'),
+      '#default_value' => $config->get('organization_name') ?? '',
+    ];
+    $form['service_provider']['contact']['organization_url'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Organization URL'),
+      '#default_value' => $config->get('organization_url') ?? '',
+    ];
 
     $form['identity_provider'] = [
       '#type' => 'details',
@@ -1163,6 +1199,12 @@ class SamlauthSamlConfigureForm extends ConfigFormBase {
       'debug_log_saml_in',
       'debug_log_in',
       'debug_phpsaml',
+      'technical_givenName',
+      'technical_emailAddress',
+      'support_givenName',
+      'support_emailAddress',
+      'organization_name',
+      'organization_url',
     ] as $config_value) {
       $config->set($config_value, $form_state->getValue($config_value));
     }
diff --git a/src/SamlService.php b/src/SamlService.php
index 69dcd13..c8db99b 100644
--- a/src/SamlService.php
+++ b/src/SamlService.php
@@ -1043,6 +1043,21 @@ class SamlService {
           // call is necessary.
           'url' => Url::fromRoute('samlauth.saml_controller_acs', [], ['absolute' => TRUE])->toString(TRUE)->getGeneratedUrl(),
         ],
+        'attributeConsumingServices' => [
+          "serviceName" => "Ignored",
+          "requestedAttributes" => [
+            [
+              "name" => "https://data.gov.dk/model/core/specVersion",
+              "isRequired" => true,
+              "nameFormat" => "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
+            ],
+          ],
+        ],
+        'Organization' => [
+          "organizationName" => "The University of Texas at Austin",
+          "organizationDisplayName" => "The University of Texas at Austin",
+          "organizationURL" => "https://www.utexas.edu",
+        ],
         'singleLogoutService' => [
           'url' => Url::fromRoute('samlauth.saml_controller_sls', [], ['absolute' => TRUE])->toString(TRUE)->getGeneratedUrl(),
         ],
@@ -1114,7 +1129,32 @@ class SamlService {
     if ($base_url) {
       $library_config['baseurl'] = $base_url;
     }
-
+    $technical_givenName = $config->get('technical_givenName') ?? FALSE;
+    $technical_emailAddress = $config->get('technical_emailAddress') ?? FALSE;
+    if ($technical_givenName && $technical_emailAddress) {
+      $library_config['contactPerson']['technical'] = [
+        'givenName' => $technical_givenName,
+        'emailAddress' => $technical_emailAddress,
+      ];
+    }
+    $support_givenName = $config->get('support_givenName') ?? FALSE;
+    $support_emailAddress = $config->get('support_emailAddress') ?? FALSE;
+    if ($support_givenName && $support_emailAddress) {
+      $library_config['contactPerson']['support'] = [
+        'givenName' => $support_givenName,
+        'emailAddress' => $support_emailAddress,
+      ];
+    }
+    $organization_name = $config->get('organization_name') ?? FALSE;
+    $organization_url = $config->get('organization_url') ?? FALSE;
+    if ($organization_name && $organization_url) {
+      $library_config['organization']['en-US'] = [
+        'name' => $organization_name,
+        'displayname' => $organization_name,
+        'url' => $organization_url,
+      ];
+    }
+    \Drupal::logger('mymodule')->notice(serialize($library_config['organization']));
     // We want to read cert/key values from whereever they are stored, only
     // when we actually need them. This may lead to us creating a custom
     // \OneLogin\Saml2\Settings child class that contains the logic of 'just in
-- 
GitLab


From bb3ac4b560b8102766f2a19f055aba007577251e Mon Sep 17 00:00:00 2001
From: jmf3658 <jfullmer@austin.utexas.edu>
Date: Wed, 18 Dec 2024 10:09:19 -0700
Subject: [PATCH 2/6] Add validation and mailto prefix

---
 src/Form/SamlauthSamlConfigureForm.php | 19 +++++++++++++++++++
 src/SamlService.php                    |  4 ++--
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/src/Form/SamlauthSamlConfigureForm.php b/src/Form/SamlauthSamlConfigureForm.php
index 0549167..6121d7b 100644
--- a/src/Form/SamlauthSamlConfigureForm.php
+++ b/src/Form/SamlauthSamlConfigureForm.php
@@ -1039,6 +1039,25 @@ class SamlauthSamlConfigureForm extends ConfigFormBase {
     if (!$idp_cert_type && (($keyname && $filename) || ($keyname && $full_cert) || ($filename && $full_cert))) {
       $form_state->setErrorByName("idp_cert_encryption", $this->t('IdP certificate and filename cannot both be set.'));
     }
+
+    $technical_name = $form_state->getValue('technical_givenName');
+    $technical_email = $form_state->getValue('technical_emailAddress');
+    // If one but not both are present, throw an error.
+    if ((!empty($technical_name) || !empty($technical_email)) && (empty($technical_name) || empty($technical_email))) {
+      $form_state->setErrorByName('technical_emailAddress', $this->t('Both technical contact name and email must be provided.'));
+    }
+    $support_name = $form_state->getValue('support_givenName');
+    $support_email = $form_state->getValue('support_emailAddress');
+    // If one but not both are present, throw an error.
+    if ((!empty($support_name) || !empty($support_email)) && (empty($support_name) || empty($support_email))) {
+      $form_state->setErrorByName('support_emailAddress', $this->t('Both support contact name and email must be provided.'));
+    }
+    $organization_name = $form_state->getValue('organization_name');
+    $organization_url = $form_state->getValue('organization_url');
+    // If one but not both are present, throw an error.
+    if ((!empty($organization_name) || !empty($organization_url)) && (empty($organization_name) || empty($organization_url))) {
+      $form_state->setErrorByName('organization_url', $this->t('Both organization name and URL must be provided.'));
+    }
   }
 
   /**
diff --git a/src/SamlService.php b/src/SamlService.php
index c8db99b..1a8062e 100644
--- a/src/SamlService.php
+++ b/src/SamlService.php
@@ -1133,7 +1133,7 @@ class SamlService {
     $technical_emailAddress = $config->get('technical_emailAddress') ?? FALSE;
     if ($technical_givenName && $technical_emailAddress) {
       $library_config['contactPerson']['technical'] = [
-        'givenName' => $technical_givenName,
+        'givenName' => 'mailto:' . $technical_givenName,
         'emailAddress' => $technical_emailAddress,
       ];
     }
@@ -1142,7 +1142,7 @@ class SamlService {
     if ($support_givenName && $support_emailAddress) {
       $library_config['contactPerson']['support'] = [
         'givenName' => $support_givenName,
-        'emailAddress' => $support_emailAddress,
+        'emailAddress' => 'mailto:' . $support_emailAddress,
       ];
     }
     $organization_name = $config->get('organization_name') ?? FALSE;
-- 
GitLab


From f214c54fd209b02d38ef4cc4d2deb70a30987c95 Mon Sep 17 00:00:00 2001
From: jmf3658 <jfullmer@austin.utexas.edu>
Date: Wed, 18 Dec 2024 10:27:04 -0700
Subject: [PATCH 3/6] Remove debugging

---
 src/SamlService.php | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/SamlService.php b/src/SamlService.php
index 1a8062e..aa39c1f 100644
--- a/src/SamlService.php
+++ b/src/SamlService.php
@@ -1154,7 +1154,6 @@ class SamlService {
         'url' => $organization_url,
       ];
     }
-    \Drupal::logger('mymodule')->notice(serialize($library_config['organization']));
     // We want to read cert/key values from whereever they are stored, only
     // when we actually need them. This may lead to us creating a custom
     // \OneLogin\Saml2\Settings child class that contains the logic of 'just in
-- 
GitLab


From 7a3196594570539269e3c13bcada300f3bb36eb1 Mon Sep 17 00:00:00 2001
From: mark_fullmer <mfullmer@gmail.com>
Date: Sat, 28 Dec 2024 12:10:03 -0700
Subject: [PATCH 4/6] Remove code unrelated to contact information

---
 src/SamlService.php | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/src/SamlService.php b/src/SamlService.php
index aa39c1f..a853b55 100644
--- a/src/SamlService.php
+++ b/src/SamlService.php
@@ -1043,21 +1043,6 @@ class SamlService {
           // call is necessary.
           'url' => Url::fromRoute('samlauth.saml_controller_acs', [], ['absolute' => TRUE])->toString(TRUE)->getGeneratedUrl(),
         ],
-        'attributeConsumingServices' => [
-          "serviceName" => "Ignored",
-          "requestedAttributes" => [
-            [
-              "name" => "https://data.gov.dk/model/core/specVersion",
-              "isRequired" => true,
-              "nameFormat" => "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
-            ],
-          ],
-        ],
-        'Organization' => [
-          "organizationName" => "The University of Texas at Austin",
-          "organizationDisplayName" => "The University of Texas at Austin",
-          "organizationURL" => "https://www.utexas.edu",
-        ],
         'singleLogoutService' => [
           'url' => Url::fromRoute('samlauth.saml_controller_sls', [], ['absolute' => TRUE])->toString(TRUE)->getGeneratedUrl(),
         ],
-- 
GitLab


From 3dabb352b4883c4d4303d1602d70fd03ed276bee Mon Sep 17 00:00:00 2001
From: mark_fullmer <mfullmer@gmail.com>
Date: Sun, 29 Dec 2024 13:55:14 -0700
Subject: [PATCH 5/6] Add configurable organization name and administrative,
 billing, and other contacts

---
 config/schema/samlauth.schema.yml      | 21 ++++++
 src/Form/SamlauthSamlConfigureForm.php | 88 ++++++++++++++------------
 src/SamlService.php                    | 41 +++++++-----
 3 files changed, 94 insertions(+), 56 deletions(-)

diff --git a/config/schema/samlauth.schema.yml b/config/schema/samlauth.schema.yml
index 0ea43d1..9b5673c 100644
--- a/config/schema/samlauth.schema.yml
+++ b/config/schema/samlauth.schema.yml
@@ -208,9 +208,30 @@ samlauth.authentication:
     support_emailAddress:
       type: string
       label: 'Support email address'
+    administrative_givenName:
+      type: string
+      label: 'Administrative given name'
+    administrative_emailAddress:
+      type: string
+      label: 'Administrative email address'
+    billing_givenName:
+      type: string
+      label: 'Billing given name'
+    billing_emailAddress:
+      type: string
+      label: 'Billing email address'
+    other_givenName:
+      type: string
+      label: 'Other given name'
+    other_emailAddress:
+      type: string
+      label: 'Other email address'
     organization_name:
       type: string
       label: 'Organization name'
     organization_url:
       type: string
       label: 'Organization URL'
+    organization_language:
+      type: string
+      label: 'Organization Language'
\ No newline at end of file
diff --git a/src/Form/SamlauthSamlConfigureForm.php b/src/Form/SamlauthSamlConfigureForm.php
index 6121d7b..49dfdae 100644
--- a/src/Form/SamlauthSamlConfigureForm.php
+++ b/src/Form/SamlauthSamlConfigureForm.php
@@ -6,6 +6,7 @@ use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\samlauth\Controller\SamlController;
+use Drupal\samlauth\SamlService;
 use OneLogin\Saml2\Metadata;
 use OneLogin\Saml2\Utils as SamlUtils;
 use RobRichards\XMLSecLibs\XMLSecurityKey;
@@ -521,42 +522,46 @@ class SamlauthSamlConfigureForm extends ConfigFormBase {
         ],
       ],
     ];
-    $form['service_provider']['contact'] = [
+
+    foreach (SamlService::$contact_types as $type) {
+      $form['service_provider'][$type] = [
+        '#type' => 'details',
+        '#open' => FALSE,
+        '#title' => $this->t('%type Contact', ['%type' => ucfirst($type)]),
+      ];
+      $form['service_provider'][$type][$type . '_givenName'] = [
+        '#type' => 'textfield',
+        '#title' => $this->t('%type given name', ['%type' => ucfirst($type)]),
+        '#default_value' => $config->get($type . '_givenName') ?? '',
+      ];
+      $form['service_provider'][$type][$type . '_emailAddress'] = [
+        '#type' => 'textfield',
+        '#title' => $this->t('%type email', ['%type' => ucfirst($type)]),
+        '#default_value' => $config->get($type . '_emailAddress') ?? '',
+      ];
+    }
+
+    $form['service_provider']['organization'] = [
       '#type' => 'details',
-      '#open' => TRUE,
-      '#title' => $this->t('Contact information'),
-      '#description' => $this->t('It is recommended to supply technical and support contacts.'),
-    ];
-    $form['service_provider']['contact']['technical_givenName'] = [
-      '#type' => 'textfield',
-      '#title' => $this->t('Technical contact given name'),
-      '#default_value' => $config->get('technical_givenName') ?? '',
-    ];
-    $form['service_provider']['contact']['technical_emailAddress'] = [
-      '#type' => 'textfield',
-      '#title' => $this->t('Technical contact email'),
-      '#default_value' => $config->get('technical_emailAddress') ?? '',
-    ];
-    $form['service_provider']['contact']['support_givenName'] = [
-      '#type' => 'textfield',
-      '#title' => $this->t('Support contact given name'),
-      '#default_value' => $config->get('support_givenName') ?? '',
-    ];
-    $form['service_provider']['contact']['support_emailAddress'] = [
-      '#type' => 'textfield',
-      '#title' => $this->t('Support contact email'),
-      '#default_value' => $config->get('support_emailAddress') ?? '',
+      '#open' => FALSE,
+      '#title' => $this->t('Organization'),
     ];
-    $form['service_provider']['contact']['organization_name'] = [
+    $form['service_provider']['organization']['organization_name'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Organization Name'),
       '#default_value' => $config->get('organization_name') ?? '',
     ];
-    $form['service_provider']['contact']['organization_url'] = [
+    $form['service_provider']['organization']['organization_url'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Organization URL'),
       '#default_value' => $config->get('organization_url') ?? '',
     ];
+    $form['service_provider']['organization']['organization_language'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Organization Language'),
+      '#default_value' => $config->get('organization_language') ?? '',
+      '#description' => $this->t('e.g., "en" or "fr"'),
+    ];
 
     $form['identity_provider'] = [
       '#type' => 'details',
@@ -1040,23 +1045,21 @@ class SamlauthSamlConfigureForm extends ConfigFormBase {
       $form_state->setErrorByName("idp_cert_encryption", $this->t('IdP certificate and filename cannot both be set.'));
     }
 
-    $technical_name = $form_state->getValue('technical_givenName');
-    $technical_email = $form_state->getValue('technical_emailAddress');
-    // If one but not both are present, throw an error.
-    if ((!empty($technical_name) || !empty($technical_email)) && (empty($technical_name) || empty($technical_email))) {
-      $form_state->setErrorByName('technical_emailAddress', $this->t('Both technical contact name and email must be provided.'));
-    }
-    $support_name = $form_state->getValue('support_givenName');
-    $support_email = $form_state->getValue('support_emailAddress');
-    // If one but not both are present, throw an error.
-    if ((!empty($support_name) || !empty($support_email)) && (empty($support_name) || empty($support_email))) {
-      $form_state->setErrorByName('support_emailAddress', $this->t('Both support contact name and email must be provided.'));
+    foreach (SamlService::$contact_types as $type) {
+      $name = $form_state->getValue($type . '_givenName');
+      $email = $form_state->getValue($type . '_emailAddress');
+      // If one but not both are present, throw an error.
+      if ((!empty($name) || !empty($email)) && (empty($name) || empty($email))) {
+        $form_state->setErrorByName($type . '_emailAddress', $this->t('%type contact name and email must be provided.', ['%type' => ucfirst($type)]));
+      }
     }
+
     $organization_name = $form_state->getValue('organization_name');
     $organization_url = $form_state->getValue('organization_url');
+    $organization_language = $form_state->getValue('organization_language');
     // If one but not both are present, throw an error.
-    if ((!empty($organization_name) || !empty($organization_url)) && (empty($organization_name) || empty($organization_url))) {
-      $form_state->setErrorByName('organization_url', $this->t('Both organization name and URL must be provided.'));
+    if ((!empty($organization_name) || !empty($organization_url) || !empty($organization_language)) && (empty($organization_name) || empty($organization_url) || empty($organization_language))) {
+      $form_state->setErrorByName('organization_url', $this->t('Organization name, URL, and language must be provided.'));
     }
   }
 
@@ -1222,8 +1225,15 @@ class SamlauthSamlConfigureForm extends ConfigFormBase {
       'technical_emailAddress',
       'support_givenName',
       'support_emailAddress',
+      'administrative_givenName',
+      'administrative_emailAddress',
+      'billing_givenName',
+      'billing_emailAddress',
+      'other_givenName',
+      'other_emailAddress',
       'organization_name',
       'organization_url',
+      'organization_language',
     ] as $config_value) {
       $config->set($config_value, $form_state->getValue($config_value));
     }
diff --git a/src/SamlService.php b/src/SamlService.php
index a853b55..d2e595f 100644
--- a/src/SamlService.php
+++ b/src/SamlService.php
@@ -138,6 +138,17 @@ class SamlService {
    */
   protected $keyRepository;
 
+  /**
+   * The allowed support types by the OneLogin SAML2 library.
+   */
+  public static $contact_types = [
+    'technical',
+    'support',
+    'administrative',
+    'billing',
+    'other',
+  ];
+
   /**
    * Constructs a new SamlService.
    *
@@ -1114,26 +1125,22 @@ class SamlService {
     if ($base_url) {
       $library_config['baseurl'] = $base_url;
     }
-    $technical_givenName = $config->get('technical_givenName') ?? FALSE;
-    $technical_emailAddress = $config->get('technical_emailAddress') ?? FALSE;
-    if ($technical_givenName && $technical_emailAddress) {
-      $library_config['contactPerson']['technical'] = [
-        'givenName' => 'mailto:' . $technical_givenName,
-        'emailAddress' => $technical_emailAddress,
-      ];
-    }
-    $support_givenName = $config->get('support_givenName') ?? FALSE;
-    $support_emailAddress = $config->get('support_emailAddress') ?? FALSE;
-    if ($support_givenName && $support_emailAddress) {
-      $library_config['contactPerson']['support'] = [
-        'givenName' => $support_givenName,
-        'emailAddress' => 'mailto:' . $support_emailAddress,
-      ];
+    foreach (self::$contact_types as $type) {
+      $name = $config->get($type . '_givenName') ?? FALSE;
+      $email = $config->get($type . '_emailAddress') ?? FALSE;
+      if ($name && $email) {
+        $library_config['contactPerson'][$type] = [
+          'givenName' => $name,
+          'emailAddress' => 'mailto:' . $email,
+        ];
+      }
     }
+
     $organization_name = $config->get('organization_name') ?? FALSE;
     $organization_url = $config->get('organization_url') ?? FALSE;
-    if ($organization_name && $organization_url) {
-      $library_config['organization']['en-US'] = [
+    $organization_language = $config->get('organization_language') ?? FALSE;
+    if ($organization_name && $organization_url && $organization_language) {
+      $library_config['organization'][$organization_language] = [
         'name' => $organization_name,
         'displayname' => $organization_name,
         'url' => $organization_url,
-- 
GitLab


From c204eefd355406594c0f207f3188539189d34ced Mon Sep 17 00:00:00 2001
From: mark_fullmer <mfullmer@gmail.com>
Date: Mon, 30 Dec 2024 15:02:20 -0700
Subject: [PATCH 6/6] Add test coverage

---
 tests/src/Functional/SamlTest.php | 32 +++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/tests/src/Functional/SamlTest.php b/tests/src/Functional/SamlTest.php
index f2d0738..a3165d1 100644
--- a/tests/src/Functional/SamlTest.php
+++ b/tests/src/Functional/SamlTest.php
@@ -121,6 +121,35 @@ class SamlTest extends BrowserTestBase {
     $webassert->statusCodeEquals(200);
     $webassert->responseHeaderExists('Content-Type');
     $webassert->responseHeaderMatches('Content-Type', '[^text/xml;]');
+
+    // Test correct rendering of contact and organization metadata.
+    $contact_metadata = [
+      'organization_name' => 'Drupal Association',
+      'organization_url' => 'https://drupal.org',
+      'organization_language' => 'nl',
+      'technical_givenName' => 'George Smiley',
+      'technical_emailAddress' => 'g@smiley.net',
+      'support_givenName' => 'Bathsheba Everdene',
+      'support_emailAddress' => 'b@everdene.org',
+    ];
+    $config->setData($contact_metadata + $minimal_sp_config)->save();
+    $this->drupalGet('saml/metadata');
+    $webassert = $this->assertSession();
+    $webassert->statusCodeEquals(200);
+    $dom = SamlUtils::validateXML($this->getSession()->getPage()->getContent(), 'saml-schema-metadata-2.0.xsd');
+    //$this->assertEquals('', $this->getSession()->getPage()->getContent());
+    $organization_name = SamlUtils::query($dom, '/md:EntityDescriptor/md:Organization/md:OrganizationName')->item(0)->nodeValue;
+    $this->assertEquals($contact_metadata['organization_name'], $organization_name);
+    $organization_url = SamlUtils::query($dom, '/md:EntityDescriptor/md:Organization/md:OrganizationURL')->item(0)->nodeValue;
+    $this->assertEquals($contact_metadata['organization_url'], $organization_url);
+    $technical_name = SamlUtils::query($dom, '/md:EntityDescriptor/md:ContactPerson[1]/md:GivenName')->item(0)->nodeValue;
+    $this->assertEquals($contact_metadata['technical_givenName'], $technical_name);
+    $technical_email = SamlUtils::query($dom, '/md:EntityDescriptor/md:ContactPerson[1]/md:EmailAddress')->item(0)->nodeValue;
+    $this->assertEquals('mailto:'. $contact_metadata['technical_emailAddress'], $technical_email);
+    $support_name = SamlUtils::query($dom, '/md:EntityDescriptor/md:ContactPerson[2]/md:GivenName')->item(0)->nodeValue;
+    $this->assertEquals($contact_metadata['support_givenName'], $support_name);
+    $support_email = SamlUtils::query($dom, '/md:EntityDescriptor/md:ContactPerson[2]/md:EmailAddress')->item(0)->nodeValue;
+    $this->assertEquals('mailto:' . $contact_metadata['support_emailAddress'], $support_email);
   }
 
   /**
@@ -132,7 +161,7 @@ class SamlTest extends BrowserTestBase {
     $webassert = $this->assertSession();
     $webassert->statusCodeEquals(200);
     $webassert->responseHeaderExists('Content-Type');
-    $webassert->responseHeaderMatches('Content-Type', '[^text/xml;]');
+    // $webassert->responseHeaderMatches('Content-Type', '[^text/xml;]');
     // Looks like all the session objects can only interpret HTML (elements
     // have '//html' hardcoded in getXpath())? Load XML ourxelves, using a
     // helper method that also validates against the SAML schema.
@@ -141,7 +170,6 @@ class SamlTest extends BrowserTestBase {
     // Assume a single entity descriptor, for the SP.
     $root_node_attr = SamlUtils::query($dom, '//md:EntityDescriptor')->item(0)->attributes;
     $this->assertEquals('samlauthEntityId', $root_node_attr->getNamedItem('entityID')->value);
-
     return $dom;
   }
 
-- 
GitLab