diff --git a/modules/adfs/lib/IdP/ADFS.php b/modules/adfs/lib/IdP/ADFS.php index 0989d11735d49477bc1afa94b24844b21fa620d1..aecba0b96b13d164877e99e285513de1674ef852 100644 --- a/modules/adfs/lib/IdP/ADFS.php +++ b/modules/adfs/lib/IdP/ADFS.php @@ -9,6 +9,11 @@ use SimpleSAML\Utils\Crypto; class ADFS { + /** + * @param \SimpleSAML\IdP $idp + * @throws \Exception + * @return void + */ public static function receiveAuthnRequest(\SimpleSAML\IdP $idp) { try { @@ -41,6 +46,15 @@ class ADFS $idp->handleAuthenticationRequest($state); } + + /** + * @param string $issuer + * @param string $target + * @param string $nameid + * @param array $attributes + * @param int $assertionLifetime + * @return string + */ private static function generateResponse($issuer, $target, $nameid, $attributes, $assertionLifetime) { $issueInstant = \SimpleSAML\Utils\Time::generateTimestamp(); @@ -49,26 +63,7 @@ class ADFS $assertionID = \SimpleSAML\Utils\Random::generateID(); $nameidFormat = 'http://schemas.xmlsoap.org/claims/UPN'; $nameid = htmlspecialchars($nameid); - - $result = <<<MSG -<wst:RequestSecurityTokenResponse xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust"> - <wst:RequestedSecurityToken> - <saml:Assertion Issuer="$issuer" IssueInstant="$issueInstant" AssertionID="$assertionID" MinorVersion="1" MajorVersion="1" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"> - <saml:Conditions NotOnOrAfter="$assertionExpire" NotBefore="$notBefore"> - <saml:AudienceRestrictionCondition> - <saml:Audience>$target</saml:Audience> - </saml:AudienceRestrictionCondition> - </saml:Conditions> - <saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified" AuthenticationInstant="$issueInstant"> - <saml:Subject> - <saml:NameIdentifier Format="$nameidFormat">$nameid</saml:NameIdentifier> - </saml:Subject> - </saml:AuthenticationStatement> - <saml:AttributeStatement> - <saml:Subject> - <saml:NameIdentifier Format="$nameidFormat">$nameid</saml:NameIdentifier> - </saml:Subject> -MSG; + $parsed_attrs = []; foreach ($attributes as $name => $values) { if ((!is_array($values)) || (count($values) == 0)) { @@ -83,31 +78,37 @@ MSG; if ((!isset($value)) || ($value === '')) { continue; } - $value = htmlspecialchars($value); - - $result .= <<<MSG - <saml:Attribute AttributeNamespace="$namespace" AttributeName="$name"> - <saml:AttributeValue>$value</saml:AttributeValue> - </saml:Attribute> -MSG; + $parsed_attrs[] = ['name' => $name, 'namespace' => $namespace, 'value' => htmlspecialchars($value)]; } } - $result .= <<<MSG - </saml:AttributeStatement> - </saml:Assertion> - </wst:RequestedSecurityToken> - <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> - <wsa:EndpointReference xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"> - <wsa:Address>$target</wsa:Address> - </wsa:EndpointReference> - </wsp:AppliesTo> -</wst:RequestSecurityTokenResponse> -MSG; - - return $result; + $config = \SimpleSAML\Configuration::getInstance(); + $t = new \SimpleSAML\XHTML\Template($config, 'adfs:generateResponse.twig'); + $twig = $t->getTwig(); + return $twig->render( + 'adfs:generateResponse.twig', + [ + 'issueInstant' => $issueInstant, + 'notBefore' => $notBefore, + 'issuer' => $issuer, + 'nameid' => $nameid, + 'nameidFormat' => $nameidFormat, + 'target' => $target, + 'assertionID' => $assertionID, + 'assertionExpire' => $assertionExpire, + 'parsedAttributes' => $parsed_attrs, + ] + ); } + + /** + * @param string $response + * @param string $key + * @param string $cert + * @param string $algo + * @return string|bool + */ private static function signResponse($response, $key, $cert, $algo) { $objXMLSecDSig = new XMLSecurityDSig(); @@ -134,6 +135,13 @@ MSG; return $responsedom->saveXML(); } + + /** + * @param string $url + * @param string $wresult + * @param string $wctx + * @return void + */ private static function postResponse($url, $wresult, $wctx) { $config = \SimpleSAML\Configuration::getInstance(); @@ -150,8 +158,8 @@ MSG; * Get the metadata of a given hosted ADFS IdP. * * @param string $entityid The entity ID of the hosted ADFS IdP whose metadata we want to fetch. - * * @return array + * * @throws \SimpleSAML\Error\Exception * @throws \SimpleSAML\Error\MetadataNotFound */ @@ -223,7 +231,7 @@ MSG; ); if (!$config->hasValue('OrganizationURL')) { - throw new \SimpleSAMl\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.'); + throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.'); } $metadata['OrganizationURL'] = $config->getLocalizedString('OrganizationURL'); } @@ -271,6 +279,12 @@ MSG; } + /** + * @param array $state + * @return void + * + * @throws \Exception + */ public static function sendResponse(array $state) { $spMetadata = $state["SPMetadata"]; @@ -323,6 +337,12 @@ MSG; ADFS::postResponse($wreply, $wresult, $wctx); } + + /** + * @param \SimpleSAML\IdP $idp + * @param array $state + * @return void + */ public static function sendLogoutResponse(\SimpleSAML\IdP $idp, array $state) { // NB:: we don't know from which SP the logout request came from @@ -332,6 +352,11 @@ MSG; ); } + + /** + * @param \SimpleSAML\IdP $idp + * @return void + */ public static function receiveLogoutMessage(\SimpleSAML\IdP $idp) { // if a redirect is to occur based on wreply, we will redirect to url as @@ -351,7 +376,14 @@ MSG; $idp->handleLogoutRequest($state, $assocId); } - // accepts an association array, and returns a URL that can be accessed to terminate the association + + /** + * Accepts an association array, and returns a URL that can be accessed to terminate the association + * @param \SimpleSAML\IdP $idp + * @param array $association + * @param string $relayState + * @return string + */ public static function getLogoutURL(\SimpleSAML\IdP $idp, array $association, $relayState) { $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler(); diff --git a/modules/adfs/lib/SAML2/XML/fed/Endpoint.php b/modules/adfs/lib/SAML2/XML/fed/Endpoint.php index d3ac56ad346d423bc21b354243dcaebae6112bb3..46b4940251b14f16e7b4615dca5fcc6e22503396 100644 --- a/modules/adfs/lib/SAML2/XML/fed/Endpoint.php +++ b/modules/adfs/lib/SAML2/XML/fed/Endpoint.php @@ -15,6 +15,8 @@ class Endpoint * * @param \DOMElement $parent The element we should append this endpoint to. * @param string $name The name of the element we should create. + * @param string $address + * @return \DOMElement */ public static function appendXML(\DOMElement $parent, $name, $address) { diff --git a/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php b/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php index de386e9f65dc932d4c112dacc3bfa8e5a5389372..e3fc90e01a78c0fba004267b98dd1af69c29bc93 100644 --- a/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php +++ b/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php @@ -20,9 +20,10 @@ class SecurityTokenServiceType extends \SAML2\XML\md\RoleDescriptor /** * The Location of Services. * - * @var string + * @var string|null */ - public $Location; + public $Location = null; + /** * Initialize a SecurityTokenServiceType element. @@ -37,6 +38,7 @@ class SecurityTokenServiceType extends \SAML2\XML\md\RoleDescriptor } } + /** * Convert this SecurityTokenServiceType RoleDescriptor to XML. * @@ -61,7 +63,7 @@ class SecurityTokenServiceType extends \SAML2\XML\md\RoleDescriptor /** * Get the location of this service. * - * @return string The full URL where this service can be reached. + * @return string|null The full URL where this service can be reached. */ public function getLocation() { @@ -73,6 +75,7 @@ class SecurityTokenServiceType extends \SAML2\XML\md\RoleDescriptor * Set the location of this service. * * @param string $location The full URL where this service can be reached. + * @return void */ public function setLocation($location) { diff --git a/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php b/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php index 5df8f3f9cccd17214333621b7800417cb4176187..659628ada5a0d3b4ea91e8ae487d436385fdc4d1 100644 --- a/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php +++ b/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php @@ -14,6 +14,7 @@ class TokenTypesOffered * Add tokentypesoffered to an XML element. * * @param \DOMElement $parent The element we should append this endpoint to. + * @return \DOMElement */ public static function appendXML(\DOMElement $parent) { diff --git a/modules/adfs/templates/generateResponse.twig b/modules/adfs/templates/generateResponse.twig new file mode 100644 index 0000000000000000000000000000000000000000..2d5f9a476b3c0572dde48f0043430c4466719099 --- /dev/null +++ b/modules/adfs/templates/generateResponse.twig @@ -0,0 +1,31 @@ +<wst:RequestSecurityTokenResponse xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust"> + <wst:RequestedSecurityToken> + <saml:Assertion Issuer="{{ issuer }}" IssueInstant="{{ issueInstant }}" AssertionID="{{ assertionID }}" MinorVersion="1" MajorVersion="1" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"> + <saml:Conditions NotOnOrAfter="{{ assertionExpire }}" NotBefore="{{ notBefore }}"> + <saml:AudienceRestrictionCondition> + <saml:Audience>{{ target }}</saml:Audience> + </saml:AudienceRestrictionCondition> + </saml:Conditions> + <saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified" AuthenticationInstant="{{ issueInstant }}"> + <saml:Subject> + <saml:NameIdentifier Format="{{ nameidFormat }}">{{ nameid }}</saml:NameIdentifier> + </saml:Subject> + </saml:AuthenticationStatement> + <saml:AttributeStatement> + <saml:Subject> + <saml:NameIdentifier Format="{{ nameidFormat }}">{{ nameid }}</saml:NameIdentifier> + </saml:Subject> +{% for attr in parsedAttributes %} + <saml:Attribute AttributeNamespace="{{ attr.namespace }}" AttributeName="{{ attr.name }}"> + <saml:AttributeValue>{{ attr.value }}</saml:AttributeValue> + </saml:Attribute> +{% endfor %} + </saml:AttributeStatement> + </saml:Assertion> + </wst:RequestedSecurityToken> + <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <wsa:EndpointReference xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"> + <wsa:Address>{{ target }}</wsa:Address> + </wsa:EndpointReference> + </wsp:AppliesTo> +</wst:RequestSecurityTokenResponse>