[manage-credentials] should not ask for Launchpad password directly

Bug #387297 reported by Leonard Richardson
22
This bug affects 1 person
Affects Status Importance Assigned to Milestone
launchpadlib
Fix Released
Undecided
Unassigned
ubuntu-dev-tools (Ubuntu)
Fix Released
Medium
Unassigned

Bug Description

Binary package hint: ubuntu-dev-tools

OAuth protects against phishing attacks, but only if we train users not to enter their Launchpad password unless 1) they're in their web browser, 2) their browser is pointed at *.launchpad.net. Nothing in the OAuth protocol itself that prevents phishing--it just makes it possible to educate users.

manage-credentials contains code to get an OAuth credential by, basically, phishing: asking the user for their Launchpad password and logging in for them. manage-credentials doesn't store the user's password or do anything bad with it, but its existence trains users to give their Launchpad password to anyone who asks for it. It also prevents users from making a decision of how much they trust the application they're using.

If it's too difficult to get credentials with launchpadlib, we need to fix launchpadlib. Subverting our security model is not the answer.

Related branches

Revision history for this message
Iain Lane (laney) wrote :

You're right, this does seem a bit suspicious. From looking at the code, it appears that this part is optional anyway, so perhaps we can just take this out and it'll use the web auth that is already in there? I'd need to test though.

fyi, the code that does the login is approve_application in ubuntutools/lp/libsupport.py

Changed in ubuntu-dev-tools (Ubuntu):
importance: Undecided → Medium
status: New → Triaged
Revision history for this message
Leonard Richardson (leonardr) wrote :
Download full text (3.5 KiB)

I'm not 100% sure by what you mean by "use the web auth", but I doubt that would be any more secure. You'd still have a random program asking for the user's Launchpad password.

I had a long talk with flacoste and mars about this. Here is the problem in a nutshell.

1. The OAuth protocol does not define how to acquire the access tokens. It happens out of band. So any way of getting the tokens is in compliance with the protocol, including manage-credentials.

2. But, if you use an untrusted client to acquire the access tokens, the untrusted client might sniff whatever credentials you use to get the access tokens. So manage-credentials trains users in bad security practice.

3. The only trusted Launchpad client is the web browser. You already type in your Launchpad password to your web browser all the time, so it's presumed to be safe. So when it's time to enter your Launchpad password, launchpadlib delegates to the web browser.

4. From a UI perspective the browser step is not great. It removes control from the application and requires the user to context-switch. The authors of end-user applications don't like or even understand this step. Here's one Leonov developer (http://www.sourcecode.de/content/some-internals):

"For example, the login and approval of Launchpadlib was a bit "strange" at the time when I looked at lplib. So I went and wrote a little wrapper class, which does the authentication and authorization (approval) automatically, without the need of a browser or interactive methods."

It was "strange", so he worked around it by having his users tell him their Launchpad passwords--exactly the thing we designed this system to avoid.

5. This is a common problem. It's happened at least twice for Launchpad: once for the Leonov desktop client and once for manage-credentials (plus anyone who uses manage-credentials this way). The Twitter web service supports OAuth with a system similar to ours, yet pretty much every Twitter client asks for your Twitter password directly.

Our tenative solution is to create trusted clients other than the web browser. We'll create a client program for command-line applications and ask people who know GTK and Qt programming to create analogous client programs for those toolkits. These programs will be similar to pinentry and they will be packaged with launchpadlib.

There are a couple problems with this. First, it doesn't scale. These client programs will only work for Launchpad's OAuth credential workflow, and it locks that workflow in place semi-permanently. That's another advantage of using the web browser--it's a general client that will present whatever interface the server defines.

Second, these client programs will be a lot easier to fake than a web browser. The command-line program, in particular, is just going to be some text on stdout. It would be trivial to hack up a fake version of the trusted client program and sniff users' passwords. So we're effectively giving up on the "trusted client" idea and falling back to the position that you "trust" any application you've installed on your system. The best we can do is provide some easy-to-use clients for various frameworks so that people don't write...

Read more...

Revision history for this message
Francis J. Lacoste (flacoste) wrote :

Martin, Matthew, I'd like to get your input from a UI perspective on this bug and associated strategy.

Revision history for this message
Stephan Rügamer (sruegamer) wrote :

Good morning,

I would like to give my input about the problems with the web browser oriented "Sign into Launchpad" approach for UI clients.

Actually, I don't think there is a difference between trusting a webbrowser and an UI client. As for leonov, we don't save any passwords somewhere in the code...this is something we need to avoid.
Yes, the password is clear-text in saved in a variable, but only as long as we need it to authenticate to launchpad. Then it's the developers task to remove those bits.

Anyhow, the problem we are approaching is, using the browser or the ui client, that you need to trust your network infrastructure, so that it really connects to launchpad and not to e.g. "vi /etc/hosts && <some internal ip> launchpad.net" or any other dns forgery.

The only way to do that, is to have openID, and to have a possibility to answer "yes, it's me who wants to sign into launchpad".

The approach with username + password is bad, but having no other chance to avoid a browser for ui clients, I think our leonov workaround is the best thing someone can do.

Regards,

\sh

Revision history for this message
Stephan Rügamer (sruegamer) wrote :

Good Morning again,

after thinking about this problem, it would be a good idea, to have a "web widget" alike. If you think that a webbrowser is the only trusted "client app", you could add a simple non cssed html page fragment with an LP auth form, which could be included in any UI client code (e.g. via qt/gtk-webkit widget), or try the openid approach.

Regards,

\sh

Revision history for this message
Leonard Richardson (leonardr) wrote :

We considered a web widget, but it's not really any better than a custom client. A random app can show you some HTML that asks for your Launchpad password, just as a random app can ask for your Launchpad password directly.

We treat the browser as a trusted client not because it displays HTML, but because the user has already entered their Launchpad password into it many times. When a third-party application asks for the Launchpad password the user must make a decision to trust that application. When a third-party application spawns a new tab in the browser the user was already using, the user doesn't have to make that decision.

We're falling back to a position of a few standard non-browser clients mainly so that people don't write their own code. Since first commenting on this bug I've heard of third-party clients that eg. crawled through the user's Firefox profile looking for a saved Launchpad password. That's just sick.

Revision history for this message
Stephan Rügamer (sruegamer) wrote :

HI,

well, another possibility would be encrypt username+password somehow with a public launchpad gpg key, which needs to be fetched from a trusted site, and with the users gpg key which is known to launchpad...

Sounds really strange, but should work...another possibilty would be to have a non-webbased-authentication via ssh, and the public key, known by LP...

I really don't see any other (sane) possibility to workaround this phishing problem.

Regards,

\sh

Revision history for this message
Leonard Richardson (leonardr) wrote :

Yeah, there are other ways to do this--Amazon's web services support something similar to what you propose. The problem is the UI. No end user is going to go through all that trouble to set something up, and application developers won't like it either.

Revision history for this message
Leonard Richardson (leonardr) wrote :
Download full text (3.8 KiB)

OK, as a non UI expert here is my proposed design for the console version of the trusted client. I would like to get Martin and Matthew's comments on this before I go too far into the implementation.

Usage:
    console-client [application name] [hostname] [oauth_token] [allow_permission, ...]

Examples:
    console-client "my application" edge.launchpad.net fJdXbM2tqrtbX3pHGxSM WRITE_PUBLIC WRITE_PRIVATE
    console-client "my application" staging.launchpad.net SMfJdXbM2tqrtbX3pHGx

Flow of execution:

Before console-client is run
============================

The client that invokes console-client must first obtain an OAuth
request token by POSTing to +request-token. launchpadlib will do this
automatically. This is not part of console-client because 1) we want the
code to be as small as possible, and 2) after console-client exits, the
calling code will need to look up the access token based on the request
token.

launchpadlib's credential-fetching methods will take an argument saying which
client should be run. The default is "browser", which will give the
current launchpadlib behavior. This document describes the "console"
behavior. "gtk" and "qt" behavior should be similar to "console", but
in a GUI window.

When console-client is run
==========================

0. Sanity check. Hostname must be .launchpad.net. Or maybe just stick
.launchpad.net onto [hostname].

1. Print intro.

   Launchpad credential client (console)
   -------------------------------------

   The application identified as "my application" wants to access
   Launchpad on your behalf. I'm the Launchpad credential client and
   I'm here to ask for your Launchpad username and password.

   I'll use your Launchpad password to give the application "my
   application" limited access to your Launchpad account. I will not
   show your password to the "my application" application itself.

   If you don't trust this client with your Launchpad password, use your web
   browser to visit this URL:
    https://[hostname]/+authorize-token?oauth_token=%(token)&allow_permission=%(allow_permission)

   Once you've authorized the application manually, hit Ctrl-C in this window to
   return to the application "my application".

2. Your Launchpad username: [input]

3. Your Launchpad password: [input, no echo]

4. GET /+authorize-token?oauth_token=%(token)&allow_permission=%(allow_permission) HTTP/1.1
   Host: %(hostname)
   Authorization=Basic %(username):%(password)
   Accept: application/json

5a. If denied access, print an error message and goto 2. Save the
    username as a default so user doesn't have to enter it again.

   Example:

   It looks like that username and password aren't valid on Launchpad.

5b. Parse the JSON result and extract the list of access levels. This
    list is automatically reconciled against any restrictions given in
    allow_permission.

7. Present the list of access levels to the end-user. Number them starting
   from 1. UNAUTHORIZED should always be displayed last and should be
   'numbered' Q.

   Example:

   How much access do you want to give "my application"?

   1: Change Non-Private Data
   2. Change Anything
   Q. No Access

8. POST /+authorize-t...

Read more...

Revision history for this message
Leonard Richardson (leonardr) wrote :

Stephan, I would also like your opinion on this workflow as a third-party developer. Would you use (a GUI version) of this client?

Revision history for this message
Stephan Rügamer (sruegamer) wrote :

Hi Leonard,

that's the very same workflow we use for leonov.
The way to go is a bit different, but regarding the implementation inside LPLIB, this is ok.

I don't see any problems with this approach.

Regards,

\sh

Revision history for this message
Leonard Richardson (leonardr) wrote :

I talked with Martin and he proposed some changes to the workflow I put up yesterday.

A. Drop the "if you don't trust this client" message. It scares people for no reason, because untrusted clients won't display that message.

B. What if the user doesn't have a Launchpad account? We'll tell them to hit enter when asked for their account, then open their browser to the Launchpad account creation page. We'll exit with a failure code. The launchpadlib application will cancel the operation and tell them to try again once they have a Launchpad account.

C. Instead of presenting "No Access" as an option called "Q", separate it out. Tell the user that if they don't like any of these options, to type Q to quit. Typing Q has the same effect as before.

Revision history for this message
Leonard Richardson (leonardr) wrote :

OK, I've written a launchpadlib branch that includes two scripts:

1. launchpad-request-token: acquires a request token
2. launchpad-credentials-console: gets the user's password and trades a request token for an access token

I wrote #1 for my own testing purposes, but it's generally useful and will stop people from reinventing the wheel. #2 is the script that I described above.

The main problem with launchpad-credentials-console is that it's talking to a website rather than a web service. There are several places where I have to infer what happened by scanning the HTML for keywords rather than relying on status codes. This makes the script fragile in the face of redesigns, even if we keep the URL format and the forms the same.

The branches are here:

https://code.edge.launchpad.net/~leonardr/launchpad/oauth-json-description
https://code.edge.launchpad.net/~leonardr/launchpadlib/trusted-client

Revision history for this message
Rolf Leggewie (r0lf) wrote :

Is this still an issue for karmic? I used requestsync for the first time today and it behaved exactly as requested here; it opened a tab in FF where I needed to allow a certain $consumer access to my launchpad account.

Revision history for this message
Leonard Richardson (leonardr) wrote :

Yes, the branch has not been reviewed or landed, so the old behavior is still present.

Changed in ubuntu-dev-tools (Ubuntu):
status: Triaged → In Progress
status: In Progress → Confirmed
Changed in launchpadlib:
status: New → In Progress
Revision history for this message
Leonard Richardson (leonardr) wrote :

After a lot of work I've gotten the branch I mentioned back in comment 13 landed in launchpadlib. We have a generic engine for asking the user for their credentials and using the credentials to authorize a request token. We also have a console-based authorizer and command line scripts for getting a request token and exchanging it for an access token.

Revision history for this message
Leonard Richardson (leonardr) wrote :

However, this code is not yet part of a released version of launchpadlib.

Revision history for this message
Stephan Rügamer (sruegamer) wrote :

Leonard,

Is it on edge somehow or staging?

Regards,

\sh

Curtis Hovey (sinzui)
Changed in launchpadlib:
status: In Progress → Triaged
Revision history for this message
Leonard Richardson (leonardr) wrote :

Stephan,

The most recently released version of launchpadlib includes the generic workflow for getting an OAuth token, but the only workflow engines implemented are the default browser-based one and a command-line-based one. To integrate this engine into your application you'll need to write your own GUI-based workflow engine or wait until someone else writes one.

Revision history for this message
Stephan Rügamer (sruegamer) wrote :

Leonard,

I'll check the CLI based one, and try to create a python class with some canonical gtk+qt widgets to have something handy for others...

Revision history for this message
Michael Vogt (mvo) wrote :

For software-center I recently created something that comes close to the gtk login widget you describe here. The code is available in http://bazaar.launchpad.net/~mvo/software-center/reviews/annotate/head%3A/utils/submit_review.py

It needs a bit of refactoring to make it a standalone widget, but it should be mostly there. Please let me know if you are interessted in it.

Revision history for this message
Stephan Rügamer (sruegamer) wrote :

Michael,

that looks promising, do you want to make a stand alone widget out of it, or should I have a look at it?

Benjamin Drung (bdrung)
summary: - manage-credentials should not ask for Launchpad password directly
+ [manage-credentials] should not ask for Launchpad password directly
Revision history for this message
Robert Collins (lifeless) wrote :

The launchpadlib side is done AFAIK.

Changed in launchpadlib:
status: Triaged → Fix Released
Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package ubuntu-dev-tools - 0.119

---------------
ubuntu-dev-tools (0.119) unstable; urgency=low

  * Support Launchpadlib 1.9. (LP: #725231, #725092)
    - Document Launchpadlib 1.9 issues in NEWS.
  * Remove manage-credentials, and credential handling code from
    ubuntutools.lp.libsupport. Launchpadlib 1.9 handles this via
    python-keyring. (LP: #387297, #645629, #689100)
  * Use Launchpadlib.login_with() directly in scripts.
  * Remove ubuntutools.lp.libsupport.approve_application, no longer used.
  * Remove ubuntutools.lp.libsupport.get_launchpad, no longer used.
  * Remove ubuntutools.lp.libsupport.translate_api_web, no longer used.
  * Skip pylint test if it crashes.
 -- Stefano Rivera <email address hidden> Tue, 01 Mar 2011 15:04:40 +0200

Changed in ubuntu-dev-tools (Ubuntu):
status: Confirmed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.