Merge lp://qastaging/~sil/desktopcouch/get-oauth-tokens-function into lp://qastaging/desktopcouch
- get-oauth-tokens-function
- Merge into trunk
Proposed by
Stuart Langridge
Status: | Rejected |
---|---|
Rejected by: | Elliot Murphy |
Proposed branch: | lp://qastaging/~sil/desktopcouch/get-oauth-tokens-function |
Merge into: | lp://qastaging/desktopcouch |
Diff against target: | None lines |
To merge this branch: | bzr merge lp://qastaging/~sil/desktopcouch/get-oauth-tokens-function |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Cole (community) | Needs Fixing | ||
Review via email:
|
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Stuart Langridge (sil) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Tim Cole (tcole) wrote : | # |
***PLEASE*** use a random.SystemRandom instance and call .choice() on that rather than using random/
review:
Needs Fixing
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Stuart Langridge (sil) wrote : | # |
> ***PLEASE*** use a random.SystemRandom instance and call .choice() on that
> rather than using random/
> credentials.
Fixed in a new branch, lp:~sil/desktopcouch/not-so-random (because this branch didn't actually add that code, this is a branch of another unmerged branch that added it).
- 39. By Stuart Langridge
-
typo
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'data/couchdb.tmpl' | |||
2 | --- data/couchdb.tmpl 2009-07-14 13:53:21 +0000 | |||
3 | +++ data/couchdb.tmpl 2009-08-20 12:55:54 +0000 | |||
4 | @@ -31,7 +31,7 @@ | |||
5 | 31 | come back to browse your CouchDB again.</p> | 31 | come back to browse your CouchDB again.</p> |
6 | 32 | <p>Don't bookmark the CouchDB page itself, because its location may change!</p> | 32 | <p>Don't bookmark the CouchDB page itself, because its location may change!</p> |
7 | 33 | <p>Taking you to your Desktop CouchDB in <span>30</span> seconds... | 33 | <p>Taking you to your Desktop CouchDB in <span>30</span> seconds... |
9 | 34 | <a id="there" href="http://localhost:[[COUCHDB_PORT]]/_utils">take me | 34 | <a id="there" href="http://[[COUCHDB_USERNAME]]:[[COUCHDB_PASSWORD]]@localhost:[[COUCHDB_PORT]]/_utils">take me |
10 | 35 | there straight away from now on</a> (remember to bookmark this page first!)</p> | 35 | there straight away from now on</a> (remember to bookmark this page first!)</p> |
11 | 36 | </body> | 36 | </body> |
12 | 37 | </html> | 37 | </html> |
13 | 38 | 38 | ||
14 | === modified file 'desktopcouch/local_files.py' | |||
15 | --- desktopcouch/local_files.py 2009-08-05 11:18:46 +0000 | |||
16 | +++ desktopcouch/local_files.py 2009-08-25 12:58:26 +0000 | |||
17 | @@ -92,6 +92,42 @@ | |||
18 | 92 | 92 | ||
19 | 93 | return chain | 93 | return chain |
20 | 94 | 94 | ||
21 | 95 | class NoOAuthTokenException(Exception): | ||
22 | 96 | def __str__(self): | ||
23 | 97 | return "OAuth details were not found in the ini file (%s)" % FILE_INI | ||
24 | 98 | |||
25 | 99 | def get_oauth_tokens(): | ||
26 | 100 | """Return the OAuth tokens from the desktop Couch ini file. | ||
27 | 101 | CouchDB OAuth is two-legged OAuth (not three-legged like most OAuth). | ||
28 | 102 | We have one "consumer", defined by a consumer_key and a secret, | ||
29 | 103 | and an "access token", defined by a token and a secret. | ||
30 | 104 | The OAuth signature is created with reference to these and the requested | ||
31 | 105 | URL. | ||
32 | 106 | (More traditional 3-legged OAuth starts with a "request token" which is | ||
33 | 107 | then used to procure an "access token". We do not require this.) | ||
34 | 108 | """ | ||
35 | 109 | import ConfigParser | ||
36 | 110 | c = ConfigParser.ConfigParser() | ||
37 | 111 | # monkeypatch ConfigParser to stop it lower-casing option names | ||
38 | 112 | c.optionxform = lambda s: s | ||
39 | 113 | c.read(FILE_INI) | ||
40 | 114 | try: | ||
41 | 115 | oauth_token_secrets = c.items("oauth_token_secretsx") | ||
42 | 116 | oauth_consumer_secrets = c.items("oauth_consumer_secrets") | ||
43 | 117 | except ConfigParser.NoSectionError: | ||
44 | 118 | raise NoOAuthTokenException | ||
45 | 119 | if not oauth_token_secrets or not oauth_consumer_secrets: | ||
46 | 120 | raise NoOAuthTokenException | ||
47 | 121 | try: | ||
48 | 122 | out = { | ||
49 | 123 | "token": oauth_token_secrets[0][0], | ||
50 | 124 | "token_secret": oauth_token_secrets[0][1], | ||
51 | 125 | "consumer_key": oauth_consumer_secrets[0][0], | ||
52 | 126 | "consumer_secret": oauth_consumer_secrets[0][1] | ||
53 | 127 | } | ||
54 | 128 | except IndexError: | ||
55 | 129 | raise NoOAuthTokenException | ||
56 | 130 | return out | ||
57 | 95 | 131 | ||
58 | 96 | # You will need to add -b or -k on the end of this | 132 | # You will need to add -b or -k on the end of this |
59 | 97 | COUCH_EXEC_COMMAND = [COUCH_EXE, couch_chain_flag(), FILE_INI, '-p', FILE_PID, | 133 | COUCH_EXEC_COMMAND = [COUCH_EXE, couch_chain_flag(), FILE_INI, '-p', FILE_PID, |
60 | 98 | 134 | ||
61 | === modified file 'desktopcouch/start_local_couchdb.py' | |||
62 | --- desktopcouch/start_local_couchdb.py 2009-08-19 16:00:01 +0000 | |||
63 | +++ desktopcouch/start_local_couchdb.py 2009-08-20 12:55:54 +0000 | |||
64 | @@ -32,14 +32,16 @@ | |||
65 | 32 | """ | 32 | """ |
66 | 33 | 33 | ||
67 | 34 | from __future__ import with_statement | 34 | from __future__ import with_statement |
69 | 35 | import os, subprocess, sys, glob | 35 | import os, subprocess, sys, glob, random, string |
70 | 36 | import desktopcouch | 36 | import desktopcouch |
71 | 37 | from desktopcouch import local_files | 37 | from desktopcouch import local_files |
72 | 38 | import xdg.BaseDirectory | 38 | import xdg.BaseDirectory |
73 | 39 | import errno | 39 | import errno |
75 | 40 | import time | 40 | import time, gtk, gnomekeyring |
76 | 41 | from desktopcouch.records.server import CouchDatabase | 41 | from desktopcouch.records.server import CouchDatabase |
77 | 42 | 42 | ||
78 | 43 | ACCEPTABLE_USERNAME_PASSWORD_CHARS = string.lowercase + string.uppercase | ||
79 | 44 | |||
80 | 43 | def dump_ini(data, filename): | 45 | def dump_ini(data, filename): |
81 | 44 | """Dump INI data with sorted sections and keywords""" | 46 | """Dump INI data with sorted sections and keywords""" |
82 | 45 | fd = open(filename, 'w') | 47 | fd = open(filename, 'w') |
83 | @@ -56,18 +58,31 @@ | |||
84 | 56 | 58 | ||
85 | 57 | def create_ini_file(): | 59 | def create_ini_file(): |
86 | 58 | """Write CouchDB ini file if not already present""" | 60 | """Write CouchDB ini file if not already present""" |
87 | 59 | # FIXME add update trigger folder | ||
88 | 60 | #update_trigger_dir = [ | ||
89 | 61 | # 'lib', 'canonical', 'ubuntuone', 'cloud_server', 'update_triggers'] | ||
90 | 62 | # | ||
91 | 63 | #timestamp_trigger = os.path.join( | ||
92 | 64 | # *update_trigger_dir + ['timestamp_trigger.py']) | ||
93 | 65 | #update_trigger = os.path.join( | ||
94 | 66 | # *update_trigger_dir + ['update_trigger.py']) | ||
95 | 67 | |||
96 | 68 | if os.path.exists(local_files.FILE_INI): | 61 | if os.path.exists(local_files.FILE_INI): |
99 | 69 | return | 62 | # load the username and password from the keyring |
100 | 70 | 63 | try: | |
101 | 64 | data = gnomekeyring.find_items_sync(gnomekeyring.ITEM_GENERIC_SECRET, | ||
102 | 65 | {'desktopcouch': 'basic'}) | ||
103 | 66 | except gnomekeyring.NoMatchError: | ||
104 | 67 | data = None | ||
105 | 68 | if data: | ||
106 | 69 | username, password = data[0].secret.split(":") | ||
107 | 70 | return username, password | ||
108 | 71 | # otherwise fall through; for some reason the access details aren't | ||
109 | 72 | # in the keyring, so re-create the ini file and do it all again | ||
110 | 73 | |||
111 | 74 | # randomly generate tokens and usernames | ||
112 | 75 | def make_random_string(count): | ||
113 | 76 | return ''.join([random.choice(ACCEPTABLE_USERNAME_PASSWORD_CHARS) | ||
114 | 77 | for x in range(count)]) | ||
115 | 78 | |||
116 | 79 | ADMIN_ACCOUNT_USERNAME = make_random_string(10) | ||
117 | 80 | ADMIN_ACCOUNT_BASIC_AUTH_PASSWORD = make_random_string(10) | ||
118 | 81 | CONSUMER_KEY = make_random_string(10) | ||
119 | 82 | CONSUMER_SECRET = make_random_string(10) | ||
120 | 83 | TOKEN = make_random_string(10) | ||
121 | 84 | TOKEN_SECRET = make_random_string(10) | ||
122 | 85 | |||
123 | 71 | local = { | 86 | local = { |
124 | 72 | 'couchdb': { | 87 | 'couchdb': { |
125 | 73 | 'database_dir': local_files.DIR_DB, | 88 | 'database_dir': local_files.DIR_DB, |
126 | @@ -81,9 +96,43 @@ | |||
127 | 81 | 'file': local_files.FILE_LOG, | 96 | 'file': local_files.FILE_LOG, |
128 | 82 | 'level': 'info', | 97 | 'level': 'info', |
129 | 83 | }, | 98 | }, |
130 | 99 | 'admins': { | ||
131 | 100 | ADMIN_ACCOUNT_USERNAME: ADMIN_ACCOUNT_BASIC_AUTH_PASSWORD | ||
132 | 101 | }, | ||
133 | 102 | 'oauth_consumer_secrets': { | ||
134 | 103 | CONSUMER_KEY: CONSUMER_SECRET | ||
135 | 104 | }, | ||
136 | 105 | 'oauth_token_secrets': { | ||
137 | 106 | TOKEN: TOKEN_SECRET | ||
138 | 107 | }, | ||
139 | 108 | 'oauth_token_users': { | ||
140 | 109 | TOKEN: ADMIN_ACCOUNT_USERNAME | ||
141 | 110 | }, | ||
142 | 111 | 'couch_httpd_auth': { | ||
143 | 112 | 'require_valid_user': 'true' | ||
144 | 113 | } | ||
145 | 84 | } | 114 | } |
146 | 85 | 115 | ||
147 | 86 | dump_ini(local, local_files.FILE_INI) | 116 | dump_ini(local, local_files.FILE_INI) |
148 | 117 | # save admin account details in keyring | ||
149 | 118 | item_id = gnomekeyring.item_create_sync( | ||
150 | 119 | None, | ||
151 | 120 | gnomekeyring.ITEM_GENERIC_SECRET, | ||
152 | 121 | 'Desktop Couch user authentication', | ||
153 | 122 | {'desktopcouch': 'basic'}, | ||
154 | 123 | "%s:%s" % (ADMIN_ACCOUNT_USERNAME, ADMIN_ACCOUNT_BASIC_AUTH_PASSWORD), | ||
155 | 124 | True) | ||
156 | 125 | # and oauth tokens | ||
157 | 126 | item_id = gnomekeyring.item_create_sync( | ||
158 | 127 | None, | ||
159 | 128 | gnomekeyring.ITEM_GENERIC_SECRET, | ||
160 | 129 | 'Desktop Couch user authentication', | ||
161 | 130 | {'desktopcouch': 'oauth'}, | ||
162 | 131 | "%s:%s:%s:%s" % (CONSUMER_KEY, CONSUMER_SECRET, TOKEN, TOKEN_SECRET), | ||
163 | 132 | True) | ||
164 | 133 | |||
165 | 134 | |||
166 | 135 | return (ADMIN_ACCOUNT_USERNAME, ADMIN_ACCOUNT_BASIC_AUTH_PASSWORD) | ||
167 | 87 | 136 | ||
168 | 88 | def run_couchdb(): | 137 | def run_couchdb(): |
169 | 89 | """Actually start the CouchDB process""" | 138 | """Actually start the CouchDB process""" |
170 | @@ -146,7 +195,7 @@ | |||
171 | 146 | # than inefficiently just overwriting it regardless | 195 | # than inefficiently just overwriting it regardless |
172 | 147 | db.add_view(view_name, mapjs, reducejs, dd_name) | 196 | db.add_view(view_name, mapjs, reducejs, dd_name) |
173 | 148 | 197 | ||
175 | 149 | def write_bookmark_file(): | 198 | def write_bookmark_file(username, password): |
176 | 150 | """Write out an HTML document that the user can bookmark to find their DB""" | 199 | """Write out an HTML document that the user can bookmark to find their DB""" |
177 | 151 | bookmark_file = os.path.join(local_files.DIR_DB, "couchdb.html") | 200 | bookmark_file = os.path.join(local_files.DIR_DB, "couchdb.html") |
178 | 152 | 201 | ||
179 | @@ -182,21 +231,24 @@ | |||
180 | 182 | pass | 231 | pass |
181 | 183 | else: | 232 | else: |
182 | 184 | fp = open(bookmark_file, "w") | 233 | fp = open(bookmark_file, "w") |
184 | 185 | fp.write(html.replace("[[COUCHDB_PORT]]", port)) | 234 | out = html.replace("[[COUCHDB_PORT]]", port) |
185 | 235 | out = out.replace("[[COUCHDB_USERNAME]]", username) | ||
186 | 236 | out = out.replace("[[COUCHDB_PASSWORD]]", password) | ||
187 | 237 | fp.write(out) | ||
188 | 186 | fp.close() | 238 | fp.close() |
189 | 187 | print "Browse your desktop CouchDB at file://%s" % \ | 239 | print "Browse your desktop CouchDB at file://%s" % \ |
190 | 188 | os.path.realpath(bookmark_file) | 240 | os.path.realpath(bookmark_file) |
191 | 189 | 241 | ||
192 | 190 | def start_couchdb(): | 242 | def start_couchdb(): |
193 | 191 | """Execute each step to start a desktop CouchDB""" | 243 | """Execute each step to start a desktop CouchDB""" |
195 | 192 | create_ini_file() | 244 | username, password = create_ini_file() |
196 | 193 | run_couchdb() | 245 | run_couchdb() |
197 | 194 | # Note that we do not call update_design_documents here. This is because | 246 | # Note that we do not call update_design_documents here. This is because |
198 | 195 | # Couch won't actually have started yet, so when update_design_documents | 247 | # Couch won't actually have started yet, so when update_design_documents |
199 | 196 | # calls the Records API, that will call back into get_pid and we end up | 248 | # calls the Records API, that will call back into get_pid and we end up |
200 | 197 | # starting Couch again. Instead, get_pid calls update_design_documents | 249 | # starting Couch again. Instead, get_pid calls update_design_documents |
201 | 198 | # *after* Couch startup has occurred. | 250 | # *after* Couch startup has occurred. |
203 | 199 | write_bookmark_file() | 251 | write_bookmark_file(username, password) |
204 | 200 | 252 | ||
205 | 201 | 253 | ||
206 | 202 | if __name__ == "__main__": | 254 | if __name__ == "__main__": |
Add a function to retrieve the OAuth token details for this desktop couch server from the ini file, which will be required by the pairing process (so they can be handed to a paired server over the network).