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>