Как аутентифицировать скрипт urllib2 для доступа к веб-сервисам HTTPS с сайта Django? - PullRequest
4 голосов
/ 22 февраля 2011

все.Я работаю над сайтом django / mod_wsgi / apache2, который обслуживает конфиденциальную информацию, используя https для всех запросов и ответов.Все представления пишутся для перенаправления, если пользователь не аутентифицирован.Он также имеет несколько представлений, которые предназначены для работы как веб-сервисы RESTful.

Сейчас я нахожусь в процессе написания сценария, который использует urllib / urllib2 для связи с некоторыми из этих служб, чтобы загрузить серию очень больших файлов.У меня возникают проблемы с ошибками 403: ЗАПРЕЩЕНО при попытке войти в систему.

(черновой вариант) метод, который я использую для аутентификации и входа в систему:

def login( base_address, username=None, password=None ):

    # prompt for the username (if needed), password
    if username == None:
        username = raw_input( 'Username: ' )
    if password == None:
        password = getpass.getpass( 'Password: ' )
    log.info( 'Logging in %s' % username )

    # fetch the login page in order to get the csrf token
    cookieHandler = urllib2.HTTPCookieProcessor()
    opener = urllib2.build_opener( urllib2.HTTPSHandler(), cookieHandler )
    urllib2.install_opener( opener )

    login_url = base_address + PATH_TO_LOGIN
    log.debug( "login_url: " + login_url )
    login_page = opener.open( login_url )

    # attempt to get the csrf token from the cookie jar
    csrf_cookie = None
    for cookie in cookieHandler.cookiejar:
        if cookie.name == 'csrftoken':
             csrf_cookie = cookie
             break
    if not cookie:
        raise IOError( "No csrf cookie found" )
    log.debug(  "found csrf cookie: " + str( csrf_cookie ) )
    log.debug(  "csrf_token = %s" % csrf_cookie.value )

    # login using the usr, pwd, and csrf token
    login_data = urllib.urlencode( dict(
        username=username, password=password,
        csrfmiddlewaretoken=csrf_cookie.value ) )
    log.debug( "login_data: %s" % login_data )

    req = urllib2.Request( login_url, login_data )
    response = urllib2.urlopen( req )
    # <--- 403: FORBIDDEN here

    log.debug( 'response url:\n' + str( response.geturl() ) + '\n' )
    log.debug( 'response info:\n' + str( response.info() ) + '\n' )

    # should redirect to the welcome page here, if back at log in - refused
    if response.geturl() == login_url:
        raise IOError( 'Authentication refused' )

    log.info( '\t%s is logged in' % username )
    # save the cookies/opener for further actions
    return opener 

Я использую HTTPCookieHandler для хранения cookie-файлов аутентификации Django на стороне сценария, чтобы я мог получить доступ к веб-службам и получить доступ к своим перенаправлениям.

Я знаю, что CSRFmiddleware для Django собирается меня поднять, если яне передавайте токен csrf вместе с информацией для входа в систему, поэтому я сначала извлекаю ее из cookiejar первой загрузки страницы / формы.Как я уже говорил, это работает с версией сайта http / development.

В частности, я получаю 403 при попытке опубликовать учетные данные на странице / форме входа через соединение https.Этот метод работает при использовании на сервере разработки, который использует соединение http.

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

Установки Python, которые я использую, обе скомпилированы с SSL.

Я также читал, что urllib2 не разрешает https-соединения через прокси.У меня не очень большой опыт работы с прокси, поэтому я не знаю, является ли использование сценария с удаленной машины прокси-соединением, и может ли это быть проблемой.Вызывает ли это проблему с доступом?

Судя по тому, что я могу сказать, проблема в сочетании файлов cookie и почтовых данных, но мне неясно, где их взять.

Любая помощь будет оценена.Спасибо

Ответы [ 2 ]

5 голосов
/ 23 февраля 2011

Пожалуйста, извините, что отвечаю на мой собственный вопрос, но - для протокола, кажется, это решило это:

Оказывается, мне нужно было установить заголовок HTTP Referer на URL страницы входа в систему в запросе, где я публикую информацию для входа.

req.add_header( 'Referer', login_url )

Причина объяснена в документации Django CSRF , в частности, шаг 4.

Из-за нашей несколько своеобразной настройки сервера, где мы используем HTTPS на производственной стороне и DEBUG = False, я не видел причину сбоя csrf_failure (в данном случае: «Сбой проверки реферира - нет реферера»), что обычно вывод в информацию отладки. Я закончил печатать эту причину ошибки в Apache error_log и STFW'd на нем. Это привело меня к code.djangoproject /.../ csrf.py и исправлению заголовка Referer.

4 голосов
/ 23 февраля 2011

Это работает на моей установке django на https, которая вдохновлена ​​вашей. Я начинаю думать, что проблема не в этом коде ... Сервер что-нибудь говорит? Я мог бы очень хорошо изучить Apache.

Я использую следующий код с моего локального компьютера на мой сервер, используя ssl на nginx, поэтому apache может быть тем местом, которое нужно искать. Я полагаю, что один из способов сузить его - это попробовать свой сценарий на моей странице входа в систему :) Скиньте мне письмо!

import urllib
import urllib2
import contextlib


def login(login_url, username, password):
    """
    Login to site
    """
    cookies = urllib2.HTTPCookieProcessor()
    opener = urllib2.build_opener(cookies)
    urllib2.install_opener(opener)

    opener.open(login_url)

    try:
        token = [x.value for x in cookies.cookiejar if x.name == 'csrftoken'][0]
    except IndexError:
        return False, "no csrftoken"

    params = dict(username=username, password=password, \
        this_is_the_login_form=True,
        csrfmiddlewaretoken=token,
         )
    encoded_params = urllib.urlencode(params)

    with contextlib.closing(opener.open(login_url, encoded_params)) as f:
        html = f.read()

        print html
        # we're in.

...