diff options
Diffstat (limited to 'modules-available/sysconfig/inc/shib.inc.php')
-rw-r--r-- | modules-available/sysconfig/inc/shib.inc.php | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/modules-available/sysconfig/inc/shib.inc.php b/modules-available/sysconfig/inc/shib.inc.php new file mode 100644 index 00000000..c3956572 --- /dev/null +++ b/modules-available/sysconfig/inc/shib.inc.php @@ -0,0 +1,150 @@ +<?php + +class Shib +{ + const SHIB_LOOKUP_JSON = '/var/cache/slx-admin/idp2suffix.json'; + + const SHIB_DISCO_JSON = '/var/cache/slx-admin/discofeed.json'; + + const RET_ERR = 0; + const RET_UPDATE = 1; + const RET_UNCHANGED = 2; + + /** + * Updates the local copy of the JSON file for mapping IDP entityIDs to scope suffixes. + * If the list changed, all ShibAuth modules will be rebuilt. + * + * @return bool true on success, or if list didn't change. false otherwise. + */ + public static function refreshIdpSuffixMap(): bool + { + $changed = false; + $ret = self::updateFromUrl(CONFIG_SHIB_LOOKUP_URL . '?what=id2suffix', self::SHIB_LOOKUP_JSON); + if ($ret === self::RET_ERR) + return false; + if ($ret === self::RET_UPDATE) { + $changed = true; + } + $ret = self::updateFromUrl(CONFIG_SHIB_DISCO_URL, self::SHIB_DISCO_JSON); + if ($ret === self::RET_ERR) + return false; + if ($ret === self::RET_UPDATE) { + $changed = true; + } + if ($changed) { + // Rebuild any modules in the background + $configs = []; + $list = ConfigModule::getAll('ShibAuth'); + $parent = null; + foreach ($list as $mod) { + $r = $mod->generate(false, $parent); + if (is_string($r)) { + $parent = $r; + } + foreach (ConfigTgz::getAllForModule($mod->id()) as $tgz) { + $configs[$tgz->id()] = $tgz; + } + } + foreach ($configs as $tgz) { + $r = $tgz->generate(false, 0, $parent); + if (is_string($r)) { + $parent = $r; + } + } + } + return $ret; + } + + private static function updateFromUrl(string $url, string $file): int + { + if (!file_exists($file) || filemtime($file) + 86400 < time()) { + $code = null; + $ret = Download::toFile($file . '.tmp', + $url, 15, $code); + if (!$ret) + return self::RET_ERR; + if (!file_exists($file) + || filesize($file) !== filesize($file . '.tmp') + || sha1_file($file, true) !== sha1_file($file . '.tmp', true) + ) { + rename($file . '.tmp', $file); + if ($code >= 200 && $code < 300) + return self::RET_UPDATE; + return self::RET_ERR; // Not 2xx range, keep file but return error + } + unlink($file . '.tmp'); + } + return self::RET_UNCHANGED; + } + + /** + * @return ?array of registrars (key) containing array{"registrar": string, "list": string[]} + */ + public static function getListByRegistrar(): ?array + { + $disco = json_decode(file_get_contents(self::SHIB_DISCO_JSON), true); + $lookup = json_decode(file_get_contents(self::SHIB_LOOKUP_JSON), true); + if (!is_array($disco) || !is_array($lookup)) { + return null; + } + foreach ($disco as $item) { + if (!isset($item['entityID'])) { + continue; + } + $id = $item['entityID']; + $name = null; + $fallback = null; + foreach ($item['DisplayNames'] ?? [] as $dn) { + if ($dn['lang'] === LANG) { + $name = $dn['value']; + } elseif ($name === null && $dn['lang'] === 'en') { + $name = $dn['value']; + } elseif ($fallback === null) { + $fallback = $dn['value']; + } + } + if ($name === null) { + $name = $fallback; + } + $registrar = $lookup[$id]['regauth'] ?? 'unknown'; + if (!isset($return[$registrar])) { + $return[$registrar] = ['list' => [], 'registrar' => $registrar]; + } + $return[$registrar]['list'][] = [ + 'id' => $id, + 'name' => $name ?? $id, + ]; + } + return $return; + } + + public static function getIdp2SuffixList(): ?array + { + $lookup = json_decode(file_get_contents(self::SHIB_LOOKUP_JSON), true); + if (!is_array($lookup)) + return null; + return $lookup; + } + + /** + * Map given list of registrar IDs back to all the IdP entityIDs they cover. + * @param string[] $regs + * @return string[] + */ + public static function explodeRegistrars(array $regs): array + { + if (empty($regs)) + return []; + $idps = []; + $reg2idps = Shib::getListByRegistrar(); + foreach ($regs as $reg) { + if (!isset($reg2idps[$reg]['list'])) + continue; + foreach ($reg2idps[$reg]['list'] as $elem) { + $idps[] = $elem['id']; + } + } + return $idps; + } + +}
\ No newline at end of file |