~ubuntu-branches/ubuntu/natty/miro/natty

« back to all changes in this revision

Viewing changes to lib/httpauth.py

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2011-01-22 02:46:33 UTC
  • mfrom: (1.4.10 upstream) (1.7.5 experimental)
  • Revision ID: james.westby@ubuntu.com-20110122024633-kjme8u93y2il5nmf
Tags: 3.5.1-1ubuntu1
* Merge from debian.  Remaining ubuntu changes:
  - Use python 2.7 instead of python 2.6
  - Relax dependency on python-dbus to >= 0.83.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Miro - an RSS based video player application
 
2
# Copyright (C) 2005-2010 Participatory Culture Foundation
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
17
#
 
18
# In addition, as a special exception, the copyright holders give
 
19
# permission to link the code of portions of this program with the OpenSSL
 
20
# library.
 
21
#
 
22
# You must obey the GNU General Public License in all respects for all of
 
23
# the code used other than OpenSSL. If you modify file(s) with this
 
24
# exception, you may extend this exception to your version of the file(s),
 
25
# but you are not obligated to do so. If you do not wish to do so, delete
 
26
# this exception statement from your version. If you delete this exception
 
27
# statement from all source files in the program, then also delete it here.
 
28
 
 
29
import os
 
30
 
 
31
from miro import config
 
32
from miro import dialogs
 
33
from miro import prefs
 
34
 
 
35
from miro.httpauthtools import HTTPPasswordList, decode_auth_header
 
36
 
 
37
def find_http_auth(url, auth_header=None):
 
38
    """Find an HTTPAuthPassword object stored in the passwords database.
 
39
 
 
40
    This method searches the database for already entered passwords.  It
 
41
    will find a string to use for the Authorization header or None.
 
42
 
 
43
    :param url: request URL
 
44
    :param auth_header: optional www-authenticate header to use to search for.
 
45
        This allows us to better match basic auth passwords
 
46
    """
 
47
    global password_list
 
48
    if auth_header is not None:
 
49
        auth_scheme, realm, domain = decode_auth_header(auth_header)
 
50
    else:
 
51
        realm = None
 
52
    return password_list.find(url, realm)
 
53
 
 
54
class CallbackTracker(object):
 
55
    """Used internally to track callbacks for dialogs for ask_for_http_auth().
 
56
 
 
57
    This class allows us to only pop up one dialog for each auth request.
 
58
    """
 
59
    def __init__(self):
 
60
        self.callback_map = {}
 
61
 
 
62
    def has_callback(self, url, realm):
 
63
        key = (url, realm)
 
64
        return key in self.callback_map
 
65
 
 
66
    def add_callback(self, callback, url, realm):
 
67
        key = (url, realm)
 
68
        callbacks = self.callback_map.setdefault(key, [])
 
69
        callbacks.append(callback)
 
70
 
 
71
    def run_callbacks(self, url, realm, username, password, auth_header):
 
72
        key = (url, realm)
 
73
        auth = password_list.add(username, password, url, auth_header)
 
74
        for callback in self.callback_map[key]:
 
75
            callback(auth)
 
76
        del self.callback_map[key]
 
77
 
 
78
    def run_canceled_callbacks(self, url, realm):
 
79
        key = (url, realm)
 
80
        for callback in self.callback_map[key]:
 
81
            callback(None)
 
82
        del self.callback_map[key]
 
83
 
 
84
def ask_for_http_auth(callback, url, auth_header, location):
 
85
    """Ask the user for a username and password to login to a site.
 
86
 
 
87
    :param callback: will be called with a HTTPAuthPassword to use, or None
 
88
    :param url: URL for the request
 
89
    :param auth_header: www-authenticate header we got from the server
 
90
    :param location: human readable text of what's requesting authorization
 
91
    """
 
92
    global password_list
 
93
 
 
94
    auth_scheme, realm, domain = decode_auth_header(auth_header)
 
95
 
 
96
    def handleLoginResponse(dialog):
 
97
        if dialog.choice == dialogs.BUTTON_OK:
 
98
            callback_tracker.run_callbacks(url, realm, dialog.username,
 
99
                    dialog.password, auth_header)
 
100
        else:
 
101
            callback_tracker.run_canceled_callbacks(url, realm)
 
102
 
 
103
    run_dialog = (not callback_tracker.has_callback(url, realm))
 
104
    callback_tracker.add_callback(callback, url, realm)
 
105
    if run_dialog:
 
106
        dialogs.HTTPAuthDialog(location, realm).run(handleLoginResponse)
 
107
 
 
108
def remove(auth):
 
109
    global password_list
 
110
    password_list.remove(auth)
 
111
 
 
112
def remove_by_url_and_realm(url, realm):
 
113
    global password_list
 
114
    auth = password_list.find(url, realm)
 
115
    if auth is not None:
 
116
        password_list.remove(auth)
 
117
 
 
118
password_list = None
 
119
callback_tracker = None
 
120
 
 
121
def init():
 
122
    global password_list
 
123
    global callback_tracker
 
124
    password_list = HTTPPasswordList()
 
125
    callback_tracker = CallbackTracker()
 
126
 
 
127
def _default_password_file():
 
128
    support_dir = config.get(prefs.SUPPORT_DIRECTORY)
 
129
    return os.path.join(support_dir, 'httpauth')
 
130
 
 
131
def restore_from_file(path=None):
 
132
    if path is None:
 
133
        path = _default_password_file()
 
134
    password_list.restore_from_file(path)
 
135
 
 
136
def write_to_file(path=None):
 
137
    if path is None:
 
138
        path = _default_password_file()
 
139
    password_list.write_to_file(path)
 
140
 
 
141
def all_passwords():
 
142
    """Get the current list of all HTTPAuthPassword objects."""
 
143
    global password_list
 
144
    return password_list.passwords
 
145
 
 
146
def add_change_callback(callback):
 
147
    """Register to get changes to the list of HTTPAuthPassword objects
 
148
 
 
149
    The callback will be called with the entire list of passwords whenever it
 
150
    is updated.
 
151
 
 
152
    :returns: a callback handle that can be passed to remove_change_callback
 
153
    """
 
154
    global password_list
 
155
    def callback_wrapper(obj, passwords):
 
156
        callback(passwords)
 
157
    return password_list.connect("passwords-updated", callback_wrapper)
 
158
 
 
159
def remove_change_callback(callback_handle):
 
160
    global password_list
 
161
    password_list.disconnect(callback_handle)