Logo Search packages:      
Sourcecode: ubuntuone-client version File versions

key_acls.py

# ubuntuone.oauthdesktop.key_acls - OAuth ACL handling for keyring
#
# Author: Stuart Langridge <stuart.langridge@canonical.com>
#
# Copyright 2009 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.
"""OAuth client authorisation code.

This code finds all apps that have pre-registered themselves as wanting to
access OAuth tokens from the Gnome keyring without the user having to approve
that, and sets ACLs on relevant keys so they can do so.

Apps pre-register themselves by dropping an ini file in 
/etc/xdg/ubuntuone/oauth_registration.d/ in which each section has keys
realm, consumer_key, exe_path, application_name.
"""

import xdg.BaseDirectory, os, ConfigParser, gnomekeyring

def get_privileged_config_folder(use_source_tree_folder=True):
    """Find the XDG config folder to use which is not the user's personal 
       config (i.e., ~/.config) so that files in it are root-owned"""
       
    # First, check for folder (if we're running from the source tree)
    if use_source_tree_folder:
        source_tree_folder = os.path.join(
             os.path.split(__file__)[0], 
             "../../../oauth_registration.d")
        if os.path.isdir(source_tree_folder):
            return os.path.join(source_tree_folder, "..")
    
    # Otherwise, check for proper XDG folders
    privileged_folders = [x for x in 
       xdg.BaseDirectory.load_config_paths('ubuntuone')
       if not x.startswith(xdg.BaseDirectory.xdg_config_home)]
    if privileged_folders:
        return privileged_folders[0]
    else:
        return None

def get_acl_preregistrations(use_source_tree_folder=True):
    "Return a list of all config files in the pre-registration folder"
    config_folder = get_privileged_config_folder(use_source_tree_folder)
    if config_folder:
        conf_dir = os.path.join(config_folder, 
          "oauth_registration.d")
        if os.path.isdir(conf_dir):
            return [os.path.join(conf_dir, x) for x in os.listdir(conf_dir)]
    return []

def get_item_ids_for_realm(realm, consumer_key):
    "Find all keyring tokens for a specific realm/consumer_key"
    if realm == "http://localhost":
        # if realm (from the config file) is localhost, then the token
        # will have ubuntuone-realm == http://localhost:SOMETHING
        # so find all keys with this consumer_key, and pass on any
        # where ubuntuone-realm begins with http://localhost:
        try:
            items = gnomekeyring.find_items_sync(
                gnomekeyring.ITEM_GENERIC_SECRET,
                {
                 'oauth-consumer-key': consumer_key})
        except (gnomekeyring.NoMatchError,
                gnomekeyring.DeniedError):
            return []
        items = [x.item_id for x in items if 
        x.attributes.get("ubuntuone-realm", "").startswith("http://localhost:")]
        return items
    else:
        # realm was not localhost, so search for it explicitly
        try:
            items = gnomekeyring.find_items_sync(
                gnomekeyring.ITEM_GENERIC_SECRET,
                {'ubuntuone-realm': realm,
                 'oauth-consumer-key': consumer_key})
        except (gnomekeyring.NoMatchError,
                gnomekeyring.DeniedError):
            return []
        return [x.item_id for x in items]

def set_single_acl(app_sets, specific_item_id=None):
    """Allow a specified set of apps to access a matching keyring 
       token without prompts"""
    for realm, consumer_key, exe_path, application_name in app_sets:
        if specific_item_id is None:
            items = get_item_ids_for_realm(realm, consumer_key)
        else:
            # item_id specified
            items = [specific_item_id]
    
        # set an ACL on the key so the calling app can read it without
        # a prompt dialog
        for item_id in items:
            acl = gnomekeyring.item_get_acl_sync(None, item_id)
            new_acls = False
            real_exe_path = os.path.realpath(exe_path)
            for acl_item in acl:
                if acl_item.get_display_name() == application_name and \
                   acl_item.get_path_name() == real_exe_path:
                    # this ACL is already set
                    break
            else:
                appref = gnomekeyring.ApplicationRef()
                ac = gnomekeyring.AccessControl(appref, 
                   gnomekeyring.ACCESS_READ | 
                   gnomekeyring.ACCESS_WRITE | gnomekeyring.ACCESS_REMOVE)
                ac.set_display_name(application_name)
                ac.set_path_name(real_exe_path)
                acl.append(ac)
                new_acls = True
            if new_acls:
                gnomekeyring.item_set_acl_sync(None, item_id, acl)
        
def set_all_key_acls(item_id=None, use_source_tree_folder=True):
    """For each file in the config folder, get the (realm, key) pair that
       the program therein is interested in and register the program as able
       to access those keys by setting an ACL on them."""
    for config_file in get_acl_preregistrations(use_source_tree_folder):
        cfp = ConfigParser.ConfigParser()
        try:
            cfp.read(config_file)
        except ConfigParser.Error:
            continue
        
        app_sets = []
        
        for section in cfp.sections():
            try:
                realm = cfp.get(section, "realm")
            except ConfigParser.NoOptionError:
                realm = None
            try:
                consumer_key = cfp.get(section, "consumer_key")
            except ConfigParser.NoOptionError:
                consumer_key = None
            try:
                exe_path = cfp.get(section, "exe_path")
            except ConfigParser.NoOptionError:
                exe_path = None
            try:
                application_name = cfp.get(section, "application_name")
            except ConfigParser.NoOptionError:
                application_name = None
            if realm and consumer_key and exe_path and application_name:
                app_sets.append((realm, consumer_key, exe_path, 
                                 application_name))
        
        if app_sets:
            set_single_acl(app_sets, specific_item_id=item_id)



Generated by  Doxygen 1.6.0   Back to index