ЭВМ/ OpenID

18.03.2010

Задумал я на базе этого блога сделать себе OpenID. OpenID — это способ идентифицировать и аутентифицировать себя на многих web-сервисах с помощью одной учетной записи. Фактически это означает, что получив один раз OpenID, можно больше не регистрироваться на сотне сайтов только ради того, чтобы читать приватные записи или писать комментарии. Конечно, эти сотни сайтов должны поддерживать OpenID. Получить OpenID можно во многих местах абсолютно бесплатно, например в том же LJ. Или настроить OpenID provider у себя в standalone блоге.

Вообще, я много лет жил без OpenID и прожил бы еще столько же, но недавно мой хороший друг уехал далеко-далеко и стал описывать свое новое житье в LJ. А так как он слегка страдает паранойей, все его записи доступны только «для друзей». Конечно, можно было завести технический аккаунт в LJ, единственной целью которого было бы предоставление доступа к приватным записям, но это совсем не комильфо.

В целом задача выглядела очень простой. Для WordPress (а этот блог работает именно на нем, если вдруг кто не понял) есть специальный плагин, который так и называется — OpenID, он предоставляет функционал как потребителя OpenID (для тех же комментариев), так и провайдера. Однако после установки плагин не заработал, так что пришлось засучить рукава и выяснять почему. Для тестирования в качестве потребителя OpenID использовался все тот же LJ.

Первое, что нагуглилось сразу — текущая версия OpenID 3.3.2 не работает с PHP 5.3, а именно его я использую по ряду причин. Патчик, исправляющий проблему, очень простой и действительно рабочий. Кроме того автор патча утверждает, что обратная совместимость не ломается, так что есть надежда, что в новой версии плагина эта проблема будет исправлена. Однако в Subversion репозитории проекта этого патча почему-то нет. На всякий случай я напомнил автору OpenID об этой проблеме.

Вторая проблема была связана с тем, что при авторизации возникал переход по адресу вида http://blog.name/index.php/openid/server…, который заканчивался ошибкой 404. Эта проблема также известна, и даже есть кривая заплатка. Чтобы понять ее причину и, главное, найти правильное решение, нужно сделать шаг в сторону и выяснить, как устроены постоянные ссылки в WP.

Постоянные ссылки на записи не меняются со временем и могут быть использованы на внешних ресурсах. По умолчанию WP генерирует постоянные ссылки вида http://blog.name/?p=123. Они не очень красиво выглядят, так как содержат в себе CGI параметры. «Красивые» ссылки вида http://blog.name/raznoe/kak-ya-provel-leto возможны при наличии mod_rewrite в Apache или соответствующих правил в конфигах lighttpd или nginx. Есть еще одна возможность, из-за которой собственно все и не работает — так называемые «почти красивые ссылки», или PATHINFO permalinks. Ссылки такого типа выглядят как http://blog.name/index.php/raznoe/kak-ya-provel-leto.

Метод PATHINFO (точнее даже PATH_INFO) работает только в Apache и использует одну его интересную особенность: по умолчанию URI вида /path/script.cgi/another/path, при наличии скрипта path/script.cgi, приводят к вызову обработчика этого скрипта, при этом устанавливается специальная переменная окружения PATH_INFO со значением равным /another/path.

У меня Apache нет, вместо него стоят nginx и php-fpm. В конфиге nginx присутствуют строчки, эмулирующие поведение mod_rewrite:

if (!-e $request_filename) {
        rewrite . /index.php last;
}

Вообще говоря, господин Сысоев всячески порицает (см. самый низ страницы) подобные конфиги, однако рекомендуемая им директива try_files присутствует только в nginx 0.7.x, тогда как у меня в Debian Lenny nginx версии 0.6.x, и менять его пока желания нет.

С nginx и его rewrite отдельная очень интересная история. Если зайти на страницу конфигурирования WP в раздел постоянных ссылок, то можно увидеть такую картинку:

Как видно, в качестве альтернативы «некрасивым» ссылкам WP предлагает использовать PATHINFO, которое не работает в nginx! Происходит это из-за того, что WP проверяет имя сервера, и если оно не Apache, или если Apache, но не загружен модуль mod_rewrite, то для постоянных ссылок по умолчанию включается режим PATHINFO. Справедливости ради надо отметить, что на самом деле правила rewrite для nginx, приведенные выше, все-таки заставляют схему с PATHINFO работать. Видимо, WP внутри себя как-то решает эту проблему. Но вот его плагины, в частности OpenID — нет, из-за чего собственно весь сыр-бор.

Так вот, оказывается, существует специальный плагин nginx Compatibility, который, во-первых, сообщает WP, что mod_rewrite как будто бы присутствует, а во-вторых, чинит какую-то проблему с FastCGI PHP SAPI, которая нас сейчас не интересует.

После активации плагина страница настроек стала выглядеть правильно:

По умолчанию предлагаются красивые mod_rewrite постоянные ссылки.

Но вернемся к OpenID. Проблема с ним заключена в нескольких строчках кода в файле common.php:

        if ($wp_rewrite->using_permalinks()) {
                $url .= 'index.php/openid/' . $service;
        } else {
                $url .= '?openid=' . $service;
        }

Автор неявно полагает, что если включены красивые постоянные ссылки, то механизм PATHINFO точно должен работать. Как было показано выше, это верно только для Apache. Таким образом если у вас не Apache (а у меня не Apache), и вы используете красивые постоянные ссылки (а я их использую), то плагин OpenID у вас работать не будет. Замечу, что без использования красивых постоянных ссылок все работает.

Горячие головы предлагают выкинуть совсем строчки, добавляющие index.php в URI, но не думаю, что автор на это согласится, все же он эти строки не зря добавил.

Чтобы найти правильный путь, нужно поставить еще один плагин — AskApache RewriteRules Viewer. Он показывает всю внутреннюю кухню постоянных ссылок:

Видно, что свойство using_permalinks, на которое опирается OpenID, действительно истинно, но свойство using_index_permalinks, которое на самом деле показывает, что работает PATHINFO, ложно. Таким образом правильным решением будет замена в вышеприведенном куске кода using_permalinks на using_index_permalinks. После того, как это было сделано, плагин успешно заработал, а соответствующий патч был отправлен автору.

, , , ,




  1. Если этот комментарий виден от «otstavnov.com», значит, рецепт сработал на связке wordpress 3.1 + nginx 0.7.67-3 + php 5.3.3-7 под стабильной Debian Squeeze.

    Спасибо.

  2. Все-таки, проблемы проявились (с принятием OpenID… а уже и с отправкой).

    Скажите, а вам не встречался за прошедшее время какой-нибудь фреймворк или удаленная служба для тестирования функциональности OpenID? Я хочу поднять с нуля экспериментальный экземпляр WP, попытаться воспроизвести свои проблемы (вообще не уверен, что проблемы на моей стороне, а не на стороне провайдера (LJ)) и отчитаться.

    • Помнится, искал я такое, но как-то безуспешно. А по поводу ЖЖ почитайте еще вот эту запись: http://disorder.ru/archives/1806. Я кстати в ЖЖ с этого бложика авторизуюсь нормально, только что проверил.

      • Спасибо, я весь тэг http://disorder.ru/archives/tag/openid внимательно, как мне кажется, прочитал.

        C LJ в связке сложно что-то тестировать просто ввиду их нестабильности (там в любой момент может снизиться доступность и пойти таймауты).

        Я сегодня тоже со своего блога авторизовался там, при том что в вашем блоге авторизация работать перестала. Но сейчас не работает их авторизация у меня, изначально работавшая.

      • Наверное, правильный вопрос, который я должен был задать, такой: а не пытались ли вы применить предлагаемый sed/using_permalinks/using_index_permalinks/ в топологии без nginx Compatibility, но с прописанным вручную значением Custom Structure=»/%year%/%monthnum%/%day%/%postname%/» в /wp-admin/options-permalink.php?

        Дело в том, что первоначально мне удалось добиться базовой функциональности OpenIP именно таким образом и опробовать ее на LJ и вашем блоге.

        Затем, перечитав это сообщение еще раз, я установил nginx Compatibility и активизировал его для php5 и проверил функциональность еще раз, но весьма небрежно. Затем мне пожаловалась знакомая, что при указании ее OpenID в форме подачи нового комментария ее уводит на пустую страницу (при этом она оказалась зарегистрированной у меня на сайте).

        Вчера я решил с этим разобраться, и мы немного поэкспериментировали. Выяснилось, что на пустую страницу ее уводят любые операции с OpenID. Я деактивировал nginx Compatibility, после чего проблема осталась только с URL, содержащими «широкие» символы UTF-8.

        Я собрался оформлять сообщение об этой локальной ошибке, но уже сегодня обнаружил, что не работает регистрация нового LJ-посетителя, и что ваш блог теперь отказывается принимать мою авторизацию.

        Хотелось бы разобраться, что произошло.

  3. Попытка авторизоваться «проблемным» wp-сайтом.