summaryrefslogtreecommitdiffstats
path: root/modules-available/sysconfig/inc/shib.inc.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/sysconfig/inc/shib.inc.php')
-rw-r--r--modules-available/sysconfig/inc/shib.inc.php150
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