2011-02-22 54 views
4

大家。 我正在使用https爲所有請求和響應提供敏感信息的django/mod_wsgi/apache2網站。如果用戶未通過身份驗證,所有視圖都會寫入重定向。它也有幾個意圖像REST風格的Web服務一樣運行的視圖。如何驗證urllib2腳本以便從Django站點訪問HTTPS Web服務?

我現在正在編寫一個腳本,它使用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在腳本端存儲Django的身份驗證Cookie,以便我可以訪問Web服務並獲取重定向。

我知道如果我沒有將csrf標記與登錄信息一起傳遞給Django,CSRFmiddleware會讓我感到困惑,所以我首先從第一頁/表單加載的cookiejar中獲取。就像我之前提到的,這可以與網站的http/development版本一起使用。

具體來說,當我試圖通過https連接將憑證發佈到登錄頁面/表單時,我得到了403。此方法在使用http連接的開發服務器上使用時有效。

沒有禁止訪問該區域的Apache目錄指令(我可以看到)。該腳本成功連接到登錄頁面,沒有發佈數據,所以我想這會讓Apache擺脫問題(但我可能是錯的)。

我正在使用的python安裝都是使用SSL編譯的。

我也讀過,urllib2不允許通過代理https連接。我對代理不太瞭解,所以我不知道從遠程機器使用腳本實際上是否是代理連接,並且這是否會成爲問題。這是否導致訪問問題?

從我所知道的問題來看,問題出在了餅乾和帖子數據的結合上,但我不清楚從哪裏拿到它。

任何幫助,將不勝感激。謝謝

回答

5

請原諒我的回答我的問題,而是 - 備案這似乎已經解決了這個問題:

事實證明,我需要設置HTTP引用頭到登錄頁面URL在我發佈登錄信息的請求中。具體而言,步驟4

由於我們有些奇特的服務器設置在這裏我們使用HTTPS的生產方和DEBUG =假,我沒有看到 -

req.add_header('Referer', login_url) 

原因是在Django CSRF documentation解釋csrf_failure失敗的原因(在這種情況下:'Referer checking failed - no referer'),通常在DEBUG信息中輸出。我最終將失敗原因打印到Apache error_log和STFW'd上。這導致我code.djangoproject/.../csrf.py和Referer頭修復。

4

這適用於我的django安裝在https上,它受到你的啓發。我開始認爲這個問題在這個代碼之外......服務器在說什麼嗎?我很可能正在考慮Apache。

我使用下面的代碼從我的本地機器到我的服務器上使用SSL的SSL,所以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. 

+0

非常感謝您關注此事並回復!我在Apache方面做了一些調試,但沒有發現任何其他內容。在嘗試幾件事情時,我最終發現了問題並回答了我自己的問題。謝謝! – carlfeberhard 2011-02-23 20:29:01