Launchpad logo and name.


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index ][Thread Index ]

[Launchpad-users] Making your launchpadlib scripts compatible with Natty launchpadlib



= Introduction =

Natty now has a new version of launchpadlib, 1.9.3. The goal of the
new version is to save your users trouble and to bring launchpadlib's
security up to the standards of the rest of Ubuntu.

Depending on how you've been using launchpadlib, you may need to make
some changes to your scripts and applications. This email describes the
new version and explains what kind of changes you might need to make.

I've already contacted every developer who has launchpadlib code in
Ubuntu, and done a little audit of their code for them. This message
is for personal scripts and for applications you've written that
aren't in Ubuntu.

If you want to test out launchpadlib in Natty, you may need to
manually install python-keyring, until bug 724327 is fixed.

Please let me know if you have any questions or if this email is unclear.

To see how the new version looks from the end-user's perspective, see this wiki page:
https://help.launchpad.net/API/ThirdPartyIntegration

= Detailed list of changes =

1. The edge server is deprecated.

You may have seen this blog post from November 2010:

http://blog.launchpad.net/general/edge-is-deprecated

In launchpadlib 1.9.3, if you try to use the 'edge' Launchpad
instance, you'll get a deprecation warning and launchpadlib will
actually use the 'production' instance.

Instead of launchpadlib.launchpad.STAGING_SERVICE_ROOT and
launchpadlib.launchpad.EDGE_SERVICE_ROOT, use the literal strings
'staging' and 'production'. Or, if you like importing constants, use
launchpadlib.uris.STAGING_SERVICE_ROOT and
launchpadlib.uris.LPNET_SERVICE_ROOT.

If you're using the literal string 'edge' to designate the edge
server, use 'production' instead.

2. Make sure you explicitly specify a Launchpad instance.

This shouldn't affect anyone, but I want to make sure. This code will
still work in 1.9.3:

>>> Launchpad.login_with("my-app")

It will run your code against the staging instance, which means that
your changes won't be saved. You probably don't use this except for
testing, which is why I don't think this will affect anyone.

In the near future, I'll probably be changing Launchpad so that there
is no default Launchpad instance. (See
https://bugs.launchpad.net/launchpadlib/+bug/714043.) The code given
above will fail, and you'll need to explicitly specify a Launchpad
instance to use:

>>> Launchpad.login_with("my-app", "production")
>>> Launchpad.login_with("my-app", "staging")
>>> Launchpad.login_with("my-app", "...")

So, as long as you're looking through your code, make this change if
necessary.

3. For interactive applications, integration is desktop-wide.

In Maverick, each application that used launchpadlib had to get its
own Launchpad credential, by launching a web browser and having the
end-user authenticate with Launchpad. This was annoying to the
end-user and was pretty useless from a security standpoint.

In Natty, the end-user has a single desktop-wide credential which is
shared by all applications. The web browser is still launched, but
it's only launched _once_, for all interactive applications (see #5
for non-interactive applications). Unless your application is the very
first one someone uses after upgrading to Natty, they won't get a
browser open.

In terms of your code, I suggest you replace calls to Launchpad() and
Launchpad.get_token_and_login() with calls to
Launchpad.login_with(). If you've got some custom code to store an
app-specific credential, you can get rid of it.

Launchpad.get_token_and_login() has been deprecated. Launchpad() is
still around, but the order of arguments has been changed slightly, so
if you're using it you should at least switch to using keyword
arguments.

The allow_access_levels argument to login_with() is still accepted,
but it doesn't do anything for interactive applications.

4. For interactive applications, the credential is stored in the
GNOME keyring

In Maverick, credentials were stored unencrypted in files on disk. In
Natty, credentials are stored in the GNOME keyring or KDE wallet. If
neither is present, credentials are stored in an encrypted file in the
user's home directory. (This is managed by the python-keyring
library.)

This is where I anticipate problems. Adding a GUI element makes
everything more complicated. For instance, if you SSH into a machine
where GNOME keyring is running and try to use a launchpadlib script,
you'll get an error if you haven't run this command:

 export `gnome-keyring-daemon`

(I've put that into my .bashrc.)

It's possible we'll also run into problems with chroots, screen
sessions, and other power-user setups. Let's find these problems now.

5. For non-interactive applications, credentials are stored in an
unencrypted file

By "non-interactive applications" I generally mean applications that
run as cronjobs. For these applications, the keyring solution won't
work, because no one is around to unlock the keyring. You need to keep
the credentials in an unencrypted file. This syntax (which you may
have seen before) will do what you want:

>>> Launchpad.login_with("my-app", "production",
   ...                      credentials_file="/path/to/file")

If /path/to/file doesn't exist, you'll get a browser open and be asked
to authorize an application-specific credential, just like in
Maverick. The credential will be written to /path/to/file, and on
subsequent runs you won't get a browser open because the credential
will be read from disk.

Because of this, if you're running an application as a cronjob, you
should either run it manually first to get the credential, or you
should generate the credential on another computer and copy the file
over to the sever that's running the cronjob.

The allow_access_levels argument to login_with() doesn't do anything
for interactive applications, but it works as before for
non-interactive applications.

6. Credentials may expire

Although the credential is used across the desktop, it may not be
permanent. The end-user has the choice to try out integration before
allowing it permanently. This means that your application may start up
with an active credential, but that it may expire after a while.

If a credential expires, launchpadlib will launch the end-user's
browser again and ask them to authorize a new credential.

This will not directly affect your code, but if you're writing an
application for other people to use, you should know that in rare
cases, your launchpadlib token might expire, causing control to shift
to the user's browser. If your user refuses to grant you a new token,
you just won't be able to use launchpadlib anymore.

This isn't technically new: the end-user always had the ability to
manually revoke your access token, and in Maverick, if they did that,
launchpadlib would simply crash. But it's a lot more prominent now,
because at least some users will choose to try out desktop integration
before making it permanent.

= Summary of changes =

1. Use 'production' instead of 'edge'.
2. Explicitly specify an instance to use, if you're not doing so already.
3. get_token_and_login is deprecated: use login_with() instead
4. Use login_with() instead of the Launchpad constructor.
5. If your script is not intended for interactive use, pass in
   a credentials_file argument to login_with() to avoid the keyring.
6. Code defensively: just because you have a valid credential when you
   start using launchpadlib doesn't mean you'll have one forever.

Leonard



This is the launchpad-users mailing list archive — see also the general help for Launchpad.net mailing lists.

(Formatted by MHonArc.)