Skip to content

django + openid: сервер своими руками (часть 1).

Под влиянием самого известного джангиста в рунете, а теперь и по совместительству агитатора за OpenID, я решил завести и себе эту модную фишку. В смысле, обзавестись OpenID. Как сторонник теории заговора (и владелец мыла в google.com, вот ведь парадокс) я решил поднимать OpenID-server у себя. Враги не должны знать куда я хожу. Ну и все такое. Ну и поскольку Django - полный рулез, буду делать все это на базе Django. Что из этого получается - смотрим (или читаем).

Компоненты:

  • собственно, Django (svn trunk)
  • библиотека python-openid (я взял версию 2.2.1)
  • apache, vim, mod_python 3.3.1 :)

Путем предварительного гугления было найдено такое решение: DjangoID. Теоретически, это уже готовая реализация сервера и клиента. Но, насколько я понял, проект заброшен. Во всяком случае последним коммитам около двух лет. И потом, я хотел бы попробовать максимально "с ноля", чтобы разобраться что, почем, где и зачем. Поэтому использовать DjangoID не будем, будем пробовать сами (настолько сами, насколько получится).

Подготовка

Думаю, базовое окружение у вас уже готово и настроено. Т.е. Django работает. Проект, в который я буду всю эту петрушку интегрировать, называется labs. Так что будьте внимательны при копипасте :) Установим библиотеку python-openid, которая будет реализовывать основной функционал сервера (ну и клиента в дальнейшем). Я выбрал самый простой путь:

easy_install -v python-openid

Библиотека установлена. Едем дальше. Качаем себе дистрибутив библиотеки (ссылка выше). Зачем? Там папка есть полезная, examples. Она нам пригодится. Распаковываем. Находим папку examples. В ней лежит djopenid. Нам туда. Оппа - да тут же полноценный Django-проект. Хмм. Интересно. Можно попробовать запустить. Но я не стал. Мне проект не нужен. Я хочу приложение. Отдельное такое себе openidserver, чтобы интегрировать его в свой проект. Вопрос о рациональности пока отложим - может быть и стоит сделать отдельный проект, но я хочу приложение. Значится, копируем папку server в свой проект. Я сразу переименовал эту папку в openidserver, для наглядности. Файлик util.py из корня демор-проекта копируем в openidserver - не люблю мусора в корне проекта. Ну и не забываем про папку templates. Из библиотеки копируем в свой склад шаблонов. Опять же, я перенес всю петрушку в templates/openidserver/. Итак, структура проекта выглядит следующим образом:

labs
    -openidserver
        --models.py, views.py, urls.py, util.py, tests.py, __init__.py
    -templates
        -openidserver
            --index.html, xrds.xml
            -core
                 --endpoint.html,idPage.html,index.html,trust.html

Начинаем настройки:

Первым делом добавлем новое приложение в setting.py:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'labs.openidserver',
)

В корневой файл urls.py добавляем информацию про новые адреса:

  ('^server/', include('labs.openidserver.urls')),

Отрываем файл openidserver/ursl.py и редактируем: 'djopenid.server.views' -> 'labs.openidserver.views'.

Следующий файл, который необходимо отредактировать: openidserver/views.py. В нем нужно поменять названия модулей, из которых импортируются функции:

Было:

from djopenid import util
from djopenid.util import getViewURL

Стало:

from labs.openidserver import util
from labs.openidserver.util import getViewURL

Так, теперь теоретически можно пробовать. Пробуем открыть адрес http://domainname.com/server ...

Оппа. Неприятнейшая ошибка:

TypeError at /server/

unsupported operand type(s) for +: 'NoneType' and 'str'

Смотрим на источник ошибки: labs/openidserver/util.py in getViewURL, line 90

Видим такую вот неприятную функцию в файле util.py:

88 def getViewURL(req, view_name_or_obj, args=None, kwargs=None):
89     relative_url = reverseURL(view_name_or_obj, args=args, kwargs=kwargs)
90     full_path = req.META.get('SCRIPT_NAME', '') + relative_url
91     return urljoin(getBaseURL(req), full_path)

Понимаем, что проблема в  META['SCRIPT_NAME']. Гуглим. Находим вот такой вот тикет. Еще гуглим. Изучаем, откуда ноги растут у этого бага. Скорее всего, окуда-то из mod_python. Огорчаемся. Мысленно взываем к Ивану и просим его рассказать как это пофиксить. А пока Иван молчит, делаем такой вот грязный хак:

88 def getViewURL(req, view_name_or_obj, args=None, kwargs=None):
89     relative_url = reverseURL(view_name_or_obj, args=args, kwargs=kwargs)
90     full_path = 'http://domainname.com' + relative_url
91 #    full_path = req.META.get('SCRIPT_NAME', '') + relative_url
92     return urljoin(getBaseURL(req), full_path)

ВНИМАНИЕ: прошу в этом месте критиков задержать дыхание и не писать что это уродство потому что... Я до конца со всей этой кухней еще не разобрался, поэтому пока не знаю где это вылезет и не придумал как обойти. Конструктив приветствуется.

Так, редактируем, сохраняем, пробуем еще раз. Снова ошибка, но в этот раз уже проще:

TemplateDoesNotExist at /server/
server/index.html

Вспоминаем, что поменяли название папки с шаблонами. Надо править пути. Благо, файл и строка известны. Правим. Не забываем, что в некоторых файлах шаблонов есть блоки  {% extends "..." %}. Их правим тоже. Прим.: ниже ссылка на архив с уже отредактированными файлами, если лениво руками править.

Итак, пробуем еще раз. Ухты! Работает:

This is an example server built for the Django framework. It only authenticates one OpenID, which is also served by this application. The OpenID it serves is

http://domainname.com/server/user/

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

Вводим адрес своего сервера, http://domainname.com/server/user, нажимаем Check и... о чудо: Associate (DH-SHA1 session) - Success!

Значит, все-таки что-то там завелось :)  В следующей части будем персонализировать наше детище.

А пока, для тех, кому лень редактировать файлы и править пути к шаблонам, архив с кодом приложения для простого OpenID сервера.

Post a Comment

Your email is never published nor shared. Required fields are marked *