@@ -408,6 +408,170 @@ private static function postResponse(string $wreply, string $wresult, ?string $w
408408 }
409409
410410
411+ /**
412+ * Get the metadata of a given hosted ADFS IdP.
413+ *
414+ * @param string $entityid The entity ID of the hosted ADFS IdP whose metadata we want to fetch.
415+ * @param \SimpleSAML\Metadata\MetaDataStorageHandler $handler Optionally the metadata storage to use,
416+ * if omitted the configured handler will be used.
417+ * @return array
418+ *
419+ * @throws \SimpleSAML\Error\Exception
420+ * @throws \SimpleSAML\Error\MetadataNotFound
421+ */
422+ public static function getHostedMetadata (string $ entityid , MetaDataStorageHandler $ handler = null ): array
423+ {
424+ $ cryptoUtils = new Utils \Crypto ();
425+
426+ $ globalConfig = Configuration::getInstance ();
427+ if ($ handler === null ) {
428+ $ handler = MetaDataStorageHandler::getMetadataHandler ($ globalConfig );
429+ }
430+ $ config = $ handler ->getMetaDataConfig ($ entityid , 'adfs-idp-hosted ' );
431+
432+ $ host = Module::getModuleURL ('adfs/idp/prp.php ' );
433+
434+ // configure endpoints
435+ $ ssob = $ handler ->getGenerated ('SingleSignOnServiceBinding ' , 'adfs-idp-hosted ' , $ host );
436+ $ slob = $ handler ->getGenerated ('SingleLogoutServiceBinding ' , 'adfs-idp-hosted ' , $ host );
437+ $ ssol = $ handler ->getGenerated ('SingleSignOnService ' , 'adfs-idp-hosted ' , $ host );
438+ $ slol = $ handler ->getGenerated ('SingleLogoutService ' , 'adfs-idp-hosted ' , $ host );
439+
440+ $ sso = [];
441+ if (is_array ($ ssob )) {
442+ foreach ($ ssob as $ binding ) {
443+ $ sso [] = [
444+ 'Binding ' => $ binding ,
445+ 'Location ' => $ ssol ,
446+ ];
447+ }
448+ } else {
449+ $ sso [] = [
450+ 'Binding ' => $ ssob ,
451+ 'Location ' => $ ssol ,
452+ ];
453+ }
454+
455+ $ slo = [];
456+ if (is_array ($ slob )) {
457+ foreach ($ slob as $ binding ) {
458+ $ slo [] = [
459+ 'Binding ' => $ binding ,
460+ 'Location ' => $ slol ,
461+ ];
462+ }
463+ } else {
464+ $ slo [] = [
465+ 'Binding ' => $ slob ,
466+ 'Location ' => $ slol ,
467+ ];
468+ }
469+
470+
471+ $ metadata = [
472+ 'metadata-set ' => 'adfs-idp-hosted ' ,
473+ 'entityid ' => $ entityid ,
474+ 'SingleSignOnService ' => $ sso ,
475+ 'SingleLogoutService ' => $ slo ,
476+ 'NameIDFormat ' => $ config ->getOptionalArrayizeString ('NameIDFormat ' , [C::NAMEID_TRANSIENT ]),
477+ 'contacts ' => [],
478+ ];
479+
480+ // add certificates
481+ $ keys = [];
482+ $ certInfo = $ cryptoUtils ->loadPublicKey ($ config , false , 'new_ ' );
483+ $ hasNewCert = false ;
484+ if ($ certInfo !== null ) {
485+ $ keys [] = [
486+ 'type ' => 'X509Certificate ' ,
487+ 'signing ' => true ,
488+ 'encryption ' => true ,
489+ 'X509Certificate ' => $ certInfo ['certData ' ],
490+ 'prefix ' => 'new_ ' ,
491+ ];
492+ $ hasNewCert = true ;
493+ }
494+
495+ /** @var array $certInfo */
496+ $ certInfo = $ cryptoUtils ->loadPublicKey ($ config , true );
497+ $ keys [] = [
498+ 'type ' => 'X509Certificate ' ,
499+ 'signing ' => true ,
500+ 'encryption ' => $ hasNewCert === false ,
501+ 'X509Certificate ' => $ certInfo ['certData ' ],
502+ 'prefix ' => '' ,
503+ ];
504+
505+ if ($ config ->hasValue ('https.certificate ' )) {
506+ /** @var array $httpsCert */
507+ $ httpsCert = $ cryptoUtils ->loadPublicKey ($ config , true , 'https. ' );
508+ $ keys [] = [
509+ 'type ' => 'X509Certificate ' ,
510+ 'signing ' => true ,
511+ 'encryption ' => false ,
512+ 'X509Certificate ' => $ httpsCert ['certData ' ],
513+ 'prefix ' => 'https. ' ,
514+ ];
515+ }
516+ $ metadata ['keys ' ] = $ keys ;
517+
518+ // add organization information
519+ if ($ config ->hasValue ('OrganizationName ' )) {
520+ $ metadata ['OrganizationName ' ] = $ config ->getLocalizedString ('OrganizationName ' );
521+ $ metadata ['OrganizationDisplayName ' ] = $ config ->getOptionalLocalizedString (
522+ 'OrganizationDisplayName ' ,
523+ $ metadata ['OrganizationName ' ],
524+ );
525+
526+ if (!$ config ->hasValue ('OrganizationURL ' )) {
527+ throw new Error \Exception ('If OrganizationName is set, OrganizationURL must also be set. ' );
528+ }
529+ $ metadata ['OrganizationURL ' ] = $ config ->getLocalizedString ('OrganizationURL ' );
530+ }
531+
532+ // add scope
533+ if ($ config ->hasValue ('scope ' )) {
534+ $ metadata ['scope ' ] = $ config ->getArray ('scope ' );
535+ }
536+
537+ // add extensions
538+ if ($ config ->hasValue ('EntityAttributes ' )) {
539+ $ metadata ['EntityAttributes ' ] = $ config ->getArray ('EntityAttributes ' );
540+
541+ // check for entity categories
542+ if (Utils \Config \Metadata::isHiddenFromDiscovery ($ metadata )) {
543+ $ metadata ['hide.from.discovery ' ] = true ;
544+ }
545+ }
546+
547+ if ($ config ->hasValue ('UIInfo ' )) {
548+ $ metadata ['UIInfo ' ] = $ config ->getArray ('UIInfo ' );
549+ }
550+
551+ if ($ config ->hasValue ('DiscoHints ' )) {
552+ $ metadata ['DiscoHints ' ] = $ config ->getArray ('DiscoHints ' );
553+ }
554+
555+ if ($ config ->hasValue ('RegistrationInfo ' )) {
556+ $ metadata ['RegistrationInfo ' ] = $ config ->getArray ('RegistrationInfo ' );
557+ }
558+
559+ // add contact information
560+ $ globalConfig = Configuration::getInstance ();
561+ $ email = $ globalConfig ->getOptionalString ('technicalcontact_email ' , null );
562+ if ($ email !== null && $ email !== 'na@example.org ' ) {
563+ $ contact = [
564+ 'emailAddress ' => $ email ,
565+ 'givenName ' => $ globalConfig ->getOptionalString ('technicalcontact_name ' , null ),
566+ 'contactType ' => 'technical ' ,
567+ ];
568+ $ metadata ['contacts ' ][] = Utils \Config \Metadata::getContact ($ contact );
569+ }
570+
571+ return $ metadata ;
572+ }
573+
574+
411575 /**
412576 * @param array $state
413577 * @throws \Exception
0 commit comments