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