diff --git a/resources/lib/UnitySSO.php b/resources/lib/UnitySSO.php index 58a48405..0495a164 100644 --- a/resources/lib/UnitySSO.php +++ b/resources/lib/UnitySSO.php @@ -26,15 +26,44 @@ private static function eppnToOrg($eppn) return strtolower($org); } + // shibboleth service provider writes attributes into "server variables" + // shibboleth service provider does not garuntee attributes are set, even REMOTE_USER + // https://shibboleth.atlassian.net/wiki/spaces/SP3/pages/2065335257/AttributeAccess + // I have observed attributes to be set to empty strings while shibd complains of bad config + private static function getAttributeRaw($attributeName, $fallbackAttributeName = null) + { + if (isset($_SERVER[$attributeName]) && $_SERVER[$attributeName] != "") { + return $_SERVER[$attributeName]; + } + if (is_null($fallbackAttributeName)) { + throw new SSOException("\$_SERVER[\"$attributeName\"] is unset or empty!"); + } + if (isset($_SERVER[$fallbackAttributeName]) && $_SERVER[$fallbackAttributeName] != "") { + return $_SERVER[$fallbackAttributeName]; + } + throw new SSOException( + "\$_SERVER[\"$attributeName\"] and \$_SERVER[\"$fallbackAttributeName\"]" + . " are both unset or empty!" + ); + } + + private static function getAttribute($attributeName, $fallbackAttributeName = null) + { + $attribute_raw = self::getAttributeRaw($attributeName, $fallbackAttributeName); + // attributes may have multiple values, by default they are split by ';' + // see SPConfig setting attributeValueDelimiter + return explode(";", $attribute_raw)[0]; + } + public static function getSSO() { return array( - "user" => self::eppnToUID($_SERVER["REMOTE_USER"]), - "org" => self::eppnToOrg($_SERVER["REMOTE_USER"]), - "firstname" => $_SERVER["givenName"], - "lastname" => $_SERVER["sn"], - "name" => $_SERVER["givenName"] . " " . $_SERVER["sn"], - "mail" => isset($_SERVER["mail"]) ? $_SERVER["mail"] : $_SERVER["eppn"] + "user" => self::eppnToUID(self::getAttribute("REMOTE_USER")), + "org" => self::eppnToOrg(self::getAttribute("REMOTE_USER")), + "firstname" => self::getAttribute("givenName"), + "lastname" => self::getAttribute("sn"), + "name" => self::getAttribute("givenName") . " " . self::getAttribute("sn"), + "mail" => self::getAttribute("mail", "eppn") ); } } diff --git a/test/phpunit-bootstrap.php b/test/phpunit-bootstrap.php index b5d1b2e7..b8919ef7 100644 --- a/test/phpunit-bootstrap.php +++ b/test/phpunit-bootstrap.php @@ -196,6 +196,23 @@ function getNonExistentUserAndExpectedUIDGIDWithCustomMapping() return [["user2001@org998.test", "foo", "bar", "user2001@org998.test"], 555]; } +function getMultipleValueAttributesAndExpectedSSO() +{ + return [ + [ + "REMOTE_USER" => "user2003@org998.test", + "givenName" => "foo;foo", + "sn" => "bar;bar", + "mail" => "user2003@org998.test;user2003@org998.test", + ], + [ + "firstname" => "foo", + "lastname" => "bar", + "mail" => "user2003@org998.test", + ] + ]; +} + function getAdminUser() { return ["user1@org1.test", "foo", "bar", "user1@org1.test"]; diff --git a/test/unit/UnitySSOTest.php b/test/unit/UnitySSOTest.php new file mode 100644 index 00000000..c61443cc --- /dev/null +++ b/test/unit/UnitySSOTest.php @@ -0,0 +1,25 @@ +assertEquals($expectedSSO["firstname"], $sso["firstname"]); + $this->assertEquals($expectedSSO["lastname"], $sso["lastname"]); + $this->assertEquals($expectedSSO["mail"], $sso["mail"]); + } finally { + $_PREVIOUS_SERVER = $_SERVER; + } + } +}