import org.kangzhang.*

Wednesday, August 26, 2009

Python keyring lib, new blog address

After three days full-time working on Java and ActionScript 3.0, I finally get time to write a post about recent news.

#1 Python keyring lib released
We've released python keyring lib four days ago. It's exciting to see my work get released, and I've created a site for it.


Address of the site: http://home.python-keyring.org

You can find our mailing list, documentation page, repository and issue list on the site. If you've any advice or question, don't hesitate to tell us.
Someone reported installation problems on our tracker. I'll try to fix these bugs and release v0.2 at this weekend.

I'd like to thanks Tarek again for his great help on this project. I've learned a lot from him on this project, and I'll continue with the project to make it better. A new post about the tips and experiences I've got in this summer will be published later, when I get a new break. :-)

#2 New domain name for this blog and new homepage for myself
I'm going to move this blog to http://blog-en.kangzhang.org. To let the subscribers of this blog see this post and re-subscribe it at new address, it will be ready after the next 12 hours.
http://home.kangzhang.org is also available now.

Sunday, July 26, 2009

Win32CryptoKeyring and CryptedFileKeyring

We've finished the keyring for Windows: Win32CryptoKeyring. It is based on the Windows's CryptAPI. CryptAPI is a set of APIs which can encrypt/decrpty the data using the login user's info. Thus, the user dose not need to type in the password when he/she is going to unlock the data.

We've also created a CryptedFileKeyring in the similar way. The difference between Win32CryptoKeyring and CryptedFileKeyring is that CryptedFileKeyring uses the AES algorithm provided by PyCrypto to encrypt/decrypt users' passwords. This results that CryptedFileKeyring need the user input their password in encryption/decryption. This may be annoying, so this keyring is not encouraged for daily use.

Both keyrings extend the BasicFileKeyring in the lib. BasicFileKeyring is the abstract base class for general file keyring which supports encryption/decryption. You can created a keyring with your encrypt/decrypt algorithms by easily extending BasicFileKeyring.

For example, here is the source code for the UncryptedFileKeyring of the lib.
class UncrpytedFileKeyring(BasicFileKeyring):
    """A simple filekeyring which dose not encrypt the password.
    """
    def filename(self):
        """Return the filename of the password file. It should be
        "keyring_password.cfg" for Windows, ".keyring_password" for other
        platforms.
        """
        import sys
        if sys.platform in ['win32']:
            return "keyring_password.cfg"
        return ".keyring_password"

    def encrypt(self, password):
        """Directly return the password itself.
        """
        return password
    def decrypt(self, password_encrypted):
        """Directly return encrypted password.
        """
        return password_encrypted

    def supported(self):
        """Applicable for all platforms, but do not recommend.
        """
        return 0
Since UncryptFileKeyring dose not encrypt the password, its implementation is simple. The BasicFileKeyring handle all file parsing/stroring affairs. Here we just need due with the encryption/decryption.

Notice that there is a supported() method for the keyring. It is a new abstract method added for the KeyringBackend. Every keyring needs implement this method to tell if it is applicable for current environment.

We've also polish the code according to PEP 008. So some method names have been changed. Here is the new definition for the KeyringBackend.
class KeyringBackend():
    """The abstract base class of the keyring, every backend must implement
    this interface.
    """
    __metaclass__ = ABCMeta

    @abstractmethod
    def supported(self):
        """Return if this keyring supports current enviroment.
        -1: not applicable
         0: suitable
         1: recommended
        """
        return -1

    @abstractmethod
    def get_password(self, service, username): 
        """Get password of the username for the service
        """
        pass

    @abstractmethod
    def set_password(self, service, username, password): 
        """Set password for the username of the service
        """
        return -1

For more information, please visit our repository.

Sunday, July 12, 2009

KWallet Porting and the Keyring Backend Selection

Last week I've finished the KDE KWallet porting of the keyring lib. And now I'm working on the keyring backend selection feature of the lib. We are going to enable the user choosing the keyring both in runtime and by the config file.

There's already a pototype demo in our demo folder(demo/keyring_demo.py). Here's some snippets from the demo.
KEYRINGRC = ".keyringrc"

def load_keyring_by_config():
    """
    This function shows how to enable a keyring using config file
    """

    # create the config file
    f = open(KEYRINGRC,'w')
    f.writelines(["[backend]\n",
                  # the path for the user created keyring
                  "keyring-path= %s\n" % str(os.path.abspath(__file__))[:-16],
                  # the name of the keyring class 
                  "default-keyring=simplekeyring.SimpleKeyring\n" ])
    f.close()

    # import the keyring lib, the lib will automaticlly load the 
    # config file and load the user defined module
    import keyring

    # invoke the keyring to store and fetch the password
    if keyring.setpass("demo-service","tarek","passexample") == 0:
        print "password stored sucessful"
    print "password", keyring.getpass("demo-service","tarek")

    os.remove(KEYRINGRC)

def set_keyring_in_runtime():
    """
    This function shows how to create a keyring manully and use it in runtime
    """

    # define a new keyring class which extends the KeyringBackend
    import keyring.backend
    class TestKeyring(keyring.backend.KeyringBackend):
        def setpass(self,servicename,username,password): return 0 
        def getpass(self,servicename,username): return "password from TestKeyring"
    
    # set the keyring for keyring lib
    import keyring
    keyring.set_keyring(TestKeyring())

    # invoke the keyring lib
    if keyring.setpass("demo-service","tarek","passexample") == 0:
        print "password stored successful"
    print "password", keyring.getpass("demo-service","tarek")

That two funtions illustrate the process of enabling a user created keyring by the config file and set the keyring in the runtime. The keyring class that load from disk is stored in demo/simplekeyring.py. Here's the definition of the keyring class.
class SimpleKeyring(KeyringBackend):
    """Simple Keyring is a keyring which can store only one
    password in memory.
    """
    def __init__(self):
        self.password = ''
    def getpass(self,servicename,username):
        return self.password
    def setpass(self,servicename,username,password):
        print "calling SimpleKeyring.setpass()"
        self.password = password
        return 0 
For more details, please refer to our repository

Tuesday, June 30, 2009

Porting to Gnome Keyring

I've finished porting the API to Gnome keyring. The latest code on the repository includes this feature. To compile the lib for gnome-keyring, you need Glibc 2.0, D-Bus 1.0 and Gnome Keyring 1.0. The changes that the keyring api made on your os can be see in the Seahorse or Gnome Keyring Manager( Deprecated).




Next platform is KDE Kwallet, here's some interesting materials .

Wednesday, June 17, 2009

Keyring Lib on OSX

Python Keyring Lib has been created on bitbucket.org. Anyone who has interest in this project can check out the latest code from that address using Mercurial.

We've finished the basic part on Mac OS X. It supports getting and setting password in Keychain.

Following screenshots show a demo. The demo stored the password, and read it from the keychain. Notice that OS X prompted a dialog to let the user unlock the keychain.


The source code of this demo can be accessed from test/demo.py in the repository.

Sunday, May 3, 2009

Call for Advices: The design issues in the Python keyring lib

About this project's idea, here's the proposal's abstract:
As the Python desktop applications grew very fast, the need for a general, platform independent keyring API ,becomes important for development. Many services require authentication before they can be used. Application always needs to store these authentications safely.

This lib is aimed to address this problem. By making a single call to this library, an application can store login information on a keyring where the application can retrieve the information—also with a single call—when needed.
For more information, you may refer to Tarek's post on the original idea and the introduction of this project.

The design of this lib has been started. Here's the main issues in the design phase:

Issue #1, the architecture of the keyring lib.
There are several ways to implement an OS related lib. I've surveyed many related work on the python binding for the keyring service. These libs are designed for GTK (Gnome-python and Micheal's work ) or OSX(Keychain.py and PcMacAdmin) . Generally speaking, there are three way to implement such a lib.
  • Method 1, use the c/c++'s python extension. This method is used by Gnome-python for their gnomekeyring binding.
  • Method 2, load the system's library through the ctypes. PyMacAdmin use this way to wrap the Keychain service of OSX.
  • Method 3, execute a external tool using commonds. Keychain.py uses this method.
We prefer method 1, since it is faster and integrated with Python better.

Issue #2, about the lib's Windows implementation.
Windows dose not provided any keyring services like the Gnome keyring and KeyChain. One good option for Windows will be to provide our own lightweight keyring system, as we have everything needed in Python itself to do so. Another possible solution is using the CryptoAPI as Subversion did.

Issue #3, the API interface of this keyring lib.
We want to hear more voice from the potential developers who'll use this lib. An initial draft can be seen in the Tarek's post. I've also made some rough thoughts after looked into Subversion's code.
Since we've decided to construct the whole lib from bottom to up, and to make the API better. This issue is not in a hurry. It will always be waiting for your suggestions.

Any advice given will be credited. Don't hesitate to leave your thoughts here.:-)

Sunday, April 26, 2009

Overview of the SVN authentication system

In the PM with Tarek on API design of the Python keyring library, he mentioned
that we should take a look at the unified authentication API used in Subversion.
So I've read the related code yesterday. And I found the work done by the
Subversion folks is really interesting and helpful for our Python keyring library.
This post is going to introduce the security model and API interface used in
Subversion project.

Following paragraphs comes from the comments in Subversion's source code.
Filename: subversion/include/auth.h
We define an authentication "provider" as a module that is able to
return a specific set of credentials. (e.g. username/password,
certificate, etc.) Each provider implements a vtable that

- can fetch initial credentials
- can retry the fetch (or try to fetch something different)
- can store the credentials for future use

For any given type of credentials, there can exist any number of
separate providers -- each provider has a different method of
fetching. (i.e. from a disk store, by prompting the user, etc.)

The application begins by creating an auth baton object, and
"registers" some number of providers with the auth baton, in a
specific order. (For example, it may first register a
username/password provider that looks in disk store, then register
a username/password provider that prompts the user.)

Later on, when any svn library is challenged, it asks the auth
baton for the specific credentials. If the initial credentials
fail to authenticate, the caller keeps requesting new credentials.
Under the hood, libsvn_auth effectively "walks" over each provider
(in order of registry), one at a time, until all the providers have
exhausted all their retry options.

This system allows an application to flexibly define authentication
behaviors (by changing registration order), and very easily write
new authentication providers.

An auth_baton also contains an internal hashtable of run-time
parameters; any provider or library layer can set these run-time
parameters at any time, so that the provider has access to the
data. (For example, certain run-time data may not be available
until an authentication challenge is made.) Each credential type
must document the run-time parameters that are made available to
its providers.
In subversion/libsvn_subr/auth.c, we can find following key
function interface used in Subversion's authentication system.
void  svn_auth_open (svn_auth_baton_t **auth_baton, apr_array_header_t *providers, apr_pool_t *pool)
void  svn_auth_set_parameter (svn_auth_baton_t *auth_baton, const char *name, const void *value)
const void *  svn_auth_get_parameter (svn_auth_baton_t *auth_baton, const char *name)
svn_error_t *  svn_auth_first_credentials (void **credentials, svn_auth_iterstate_t **state, const char *cred_kind, const char *realmstring, svn_auth_baton_t *auth_baton, apr_pool_t *pool)
svn_error_t *  svn_auth_next_credentials (void **credentials, svn_auth_iterstate_t *state, apr_pool_t *pool)
svn_error_t *  svn_auth_save_credentials (svn_auth_iterstate_t *state, apr_pool_t *pool)
When the SVN library asked for the authentication, it first initialize the baton
by calling svn_auth_open(). Then it'll set the needed parameter through
svn_auth_set_parameter(). Finally, it can get the credentials using
svn_auth_first_credentials and svn_auth_next_credentials. Note that the
baton is initialize with a list of providers. When it is asked for credentials,
it'll try to fetch the credentials in that list's order.