SimpleSAML и Error parsing XML string

Данная ошибка начала возникать после обновления simpleSAML. Причём появляется только на один из ресурсов на который настроено SSO и не у всех, а у нескольких человек. С чем конкретно связано — пока неясно. Начал исследовать, что общего у этих проблемных человек — только то, что работают с одним внешним ресурсом и всё. Не густо…

Гугление мало чем помогло и сначала наткнулся на эту статью, поставил плагин и начал дебажить, но это ничего не дало. Ведь по факту, идёт ругань на самом SSO, то есть SimpleSAML.

Придётся дебажить код php (а я его плохо знаю).

Полный текст ошибки выглядит так

SimpleSAML\Error\Error: UNHANDLEDEXCEPTION

Backtrace:
1 www/_include.php:17 (SimpleSAML_exception_handler)
0 [builtin] (N/A)
Caused by: DOMException: Error parsing XML string.
Backtrace:
15 lib/SimpleSAML/Utils/XML.php:270 (SimpleSAML\Utils\XML::formatXMLString)
14 lib/SimpleSAML/Utils/XML.php:148 (SimpleSAML\Utils\XML::debugSAMLMessage)
13 vendor/simplesamlphp/saml2/src/SAML2/Compat/Ssp/Container.php:62 (SAML2\Compat\Ssp\Container::debugMessage)
12 vendor/simplesamlphp/saml2/src/SAML2/HTTPPost.php:36 (SAML2\HTTPPost::send)
11 modules/saml/lib/IdP/SAML2.php:117 (SimpleSAML\Module\saml\IdP\SAML2::sendResponse)
10 [builtin] (call_user_func)
9 lib/SimpleSAML/IdP.php:290 (SimpleSAML\IdP::postAuthProc)
8 lib/SimpleSAML/IdP.php:337 (SimpleSAML\IdP::postAuth)
7 [builtin] (call_user_func)
6 lib/SimpleSAML/Auth/Source.php:248 (SimpleSAML\Auth\Source::loginCompleted)
5 [builtin] (call_user_func)
4 lib/SimpleSAML/Auth/Source.php:161 (SimpleSAML\Auth\Source::completeAuth)
3 modules/core/lib/Auth/UserPassBase.php:331 (SimpleSAML\Module\core\Auth\UserPassBase::handleLogin)
2 modules/core/www/loginuserpass.php:84 (require)
1 lib/SimpleSAML/Module.php:266 (SimpleSAML\Module::process)
0 www/module.php:10 (N/A)

Лезу в lib/SimpleSAML/Utils/XML.php в строку 270 и хочу понять, что такого плохого содержится в создаваемом XML, что нельзя его распарсить. Да, скорее всего это либо незакрытый тег, либо non-ASCII символ. До этого ещё раз проверил все поля в ldap’e проблемного юзера на предмет non-ASCII — и это ничего не дало (как позже оказалось, всё-таки не все проверил, но это было сюрпризом). В итоге, вставляю такой код перед try:

//debug ON
        file_put_contents('/tmp/saml.log', '=============================================================================================', FILE_APPEND);
        file_put_contents('/tmp/saml.log', $xml, FILE_APPEND);
//debug OFF

        try {
            $doc = DOMDocumentFactory::fromString($xml);
        } catch (\Exception $e) {

После этого в логе уже виден весь формирующий XML и действительно, там есть non-ASCII символы. Но откуда? Идём от них до ближайшего атрибута ldap’a и… это оказался jpegphoto! Почему на старой версии работает а в новой нет? Полез разбираться с vendor/simplesamlphp/saml2/src/SAML2/DOMDocumentFactory.php, где описан данный класс, но не вышло ((. Дальше была идея запретить передачу остальных атрибутов, то есть в конфиге для нужного SP в metadata выставить

'simplesaml.attributes' => FALSE,

но получаем ошибку на стороне стороннего сервиса:

There is no AttributeStatement on the Response

Советы из гугла не помогают, так как они касаются всего, но не simpleSAML. Общий принцип понятен, что нужно сделать, но как это сделать конкретно в SimpleSAML — узнать не удалось. Опять неудача. Но ход мыслей верный.

Новое гугление натолкнуло на это. Но в моей версии этот модуль был сильно переписан и перемещён в другое место, что по шаблону jpegphoto не находит никаких strtolower, к чему хотя бы можно было приложиться.

Последующее гугление натолкнуло на мысль, а не завернуть ли картинку в base64? Тут же нашёлся соответствующий параметр

'base64attributes' => true,

но и тут не всё гладко, хотя авторизация на SAML прошла и даже пустило в сторонний сервис, с одной оговоркой: теперь все ldap-параметры идут закодированные base64, даже login )). Тут тоже промах.

Нужно как-то запретить передачу атрибута jpegphoto. Гугление не помогло. Решил зайти с другой стороны, а именно, разрешить передачу только нужных атрибутов, таких как login/email/name/surname. И…. это сработало! В итоге, решением является такая строка:

'attributes' => ['uid', 'mail', 'givenName', 'cn'],

Вот как это выглядит в рабочем варианте

$metadata['https://domain.com/saml/metadata/organisation/'] = [
        'AssertionConsumerService' => 'https://domain.com/saml/acs/organisation/',
        'simplesaml.nameidattribute' => 'mail',
        'simplesaml.nameidattribute' => 'uid',
        'attributes' => ['uid', 'mail', 'givenName', 'cn'],

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *