~ubuntu-branches/ubuntu/precise/desktopcouch/precise

« back to all changes in this revision

Viewing changes to desktopcouch/application/platform/windows/keyring.py

  • Committer: Bazaar Package Importer
  • Author(s): Chad MILLER
  • Date: 2011-01-12 15:08:25 UTC
  • mfrom: (1.5.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20110112150825-bzvn23kzufr0qdyb
Tags: 1.0.5-0ubuntu1
* New upstream release, skipping a few buggy releases.
* Split code into binary packages:
  - desktopcouch, configuration files and dependencies, but no code.
  - python-desktopcouch: transitional package
  - python-desktopcouch-application: local DB startup and discovery
  - python-desktopcouch-records: library for DB access anywhere
  - python-desktopcouch-recordtypes: support specific data structures
  - desktopcouch-ubuntuone, replication and pairing with cloud service
* Drop patch that some maverick apps incorrectly needed.
  patches/0-items-should-expose-private-data-for-now.patch
* Update package compatibility-version, 6 -> 7.
* Use newer debhelper and use python-support instead of python-central.
* Depend on contemporary python-couchdb, instead of ancient version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2009 Canonical Ltd.
 
2
#
 
3
# This file is part of desktopcouch.
 
4
#
 
5
#  desktopcouch is free software: you can redistribute it and/or modify
 
6
# it under the terms of the GNU Lesser General Public License version 3
 
7
# as published by the Free Software Foundation.
 
8
#
 
9
# desktopcouch is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU Lesser General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU Lesser General Public License
 
15
# along with desktopcouch.  If not, see <http://www.gnu.org/licenses/>.
 
16
#
 
17
# Author: Manuel de la Pena <manuel.delapena@canonical.com>
 
18
"""Keyring  implementation on windows."""
 
19
 
 
20
import base64
 
21
 
 
22
from itertools import count
 
23
 
 
24
from desktopcouch.application.util import make_random_string
 
25
 
 
26
 
 
27
class Keyring(object):
 
28
    """Implementation to be used on windows.
 
29
 
 
30
    Provides the implementation of the keyring operations on windows
 
31
    using the crypto lib and the registry key to store the info.
 
32
    """
 
33
 
 
34
    def __init__(self, make_random_string_fn=make_random_string,
 
35
                 registry=None, crypto=None):
 
36
        super(Keyring, self).__init__()
 
37
        # ignore pylint, we might not be on windows
 
38
        # pylint: disable=F0401
 
39
        if registry is None:
 
40
            import _winreg
 
41
            registry = _winreg
 
42
 
 
43
        if crypto is None:
 
44
            import win32crypt
 
45
            crypto = win32crypt
 
46
        # pylint: enable=F0401
 
47
 
 
48
        self.make_random_string = make_random_string_fn
 
49
        self.registry = registry
 
50
        self.crypto = crypto
 
51
 
 
52
    def _registry_value_exists(self, value):
 
53
        """Return if the required key exists in the system."""
 
54
        # ignore the fact that we do not specify the expcetion, we do
 
55
        # this so that the tests can run on linux.
 
56
        # pylint: disable=W0702
 
57
        # try to open it, if not, return false
 
58
        try:
 
59
            access_rights = self.registry.KEY_ALL_ACCESS
 
60
            canonical = self.registry.OpenKey(self.registry.HKEY_CURRENT_USER,
 
61
                'Canonical', 0, access_rights)
 
62
            keyrings = self.registry.OpenKey(canonical,
 
63
                'Keyrings', 0, access_rights)
 
64
            default = self.registry.OpenKey(keyrings,
 
65
                'Default', 0, access_rights)
 
66
            desktopcouch = self.registry.OpenKey(default,
 
67
                'Desktopcouch', 0, access_rights)
 
68
            # enum until we get a exception
 
69
            for index in count():
 
70
                try:
 
71
                    info = self.registry.EnumValue(
 
72
                        desktopcouch, index)
 
73
                    if info[0] == value:
 
74
                        return True
 
75
                except:
 
76
                    return False
 
77
        except:
 
78
            return False
 
79
        # pylint: enable=W0702
 
80
 
 
81
    def _open_registry_key(self):
 
82
        """Open the required registry key"""
 
83
        # we need to open the key from the keyring location in the
 
84
        # registry, the easiest way is to open step by step each key
 
85
        # using CreateKey since it will create the key if required
 
86
        canonical_key = self.registry.CreateKey(
 
87
            self.registry.HKEY_CURRENT_USER,
 
88
            'Canonical')
 
89
        keyring_key = self.registry.CreateKey(
 
90
            canonical_key, 'Keyrings')
 
91
        default_key = self.registry.CreateKey(
 
92
            keyring_key, 'Default')
 
93
        return self.registry.CreateKey(
 
94
            default_key, 'Desktopcouch')
 
95
 
 
96
    def get_user_name_password(self):
 
97
        """Return the user name and passwd used to access desktopcouch."""
 
98
        admin_username = None
 
99
        admin_password = None
 
100
        data_exists = self._registry_value_exists('basic')
 
101
        key = self._open_registry_key()
 
102
        if data_exists:
 
103
            # read and return it
 
104
            secret = self.registry.QueryValueEx(key, 'basic')
 
105
            secret = base64.b64decode(secret[0])
 
106
            secret = self.crypto.CryptUnprotectData(secret,
 
107
                None, None, None, 0)
 
108
            admin_username, admin_password = secret[1].split(':', 1)
 
109
        else:
 
110
            admin_username = self.make_random_string(10)
 
111
            admin_password = self.make_random_string(10)
 
112
            # encrypt the info before we store it
 
113
            secret = ':'.join([admin_username, admin_password])
 
114
            secret = self.crypto.CryptProtectData(
 
115
                secret, u'basic', None, None, None, 0)
 
116
            secret = base64.b64encode(secret)
 
117
            # store the secured data
 
118
            self.registry.SetValueEx(key, 'basic', 0, self.registry.REG_SZ,
 
119
                secret)
 
120
        return (admin_username, admin_password)
 
121
 
 
122
    def get_oauth_data(self):
 
123
        """Return the oauth data used to connect with couchdb."""
 
124
        consumer_key = self.make_random_string(10)
 
125
        consumer_secret = self.make_random_string(10)
 
126
        token = self.make_random_string(10)
 
127
        token_secret = self.make_random_string(10)
 
128
        # Save the new OAuth creds so that 3rd-party apps can
 
129
        # authenticate by accessing the keyring first.  This is
 
130
        # one-way.  We don't read from keyring.
 
131
        key = self._open_registry_key()
 
132
        secret = ':'.join([consumer_key, consumer_secret, token, token_secret])
 
133
        secret = self.crypto.CryptProtectData(secret, u'oauth',
 
134
            None, None, None, 0)
 
135
        secret = base64.b64encode(secret)
 
136
        self.registry.SetValueEx(key, 'oauth', 0, self.registry.REG_SZ,
 
137
            secret)
 
138
        return (consumer_key, consumer_secret, token, token_secret)
 
139
 
 
140
 
 
141
class TestKeyring(object):
 
142
    """Keyring that will store the secrets on memory for testing reasons."""
 
143
 
 
144
    def __init__(self):
 
145
        """Create a new instance of the class."""
 
146
        self.items = {}
 
147
 
 
148
    def get_user_name_password(self):
 
149
        """Get username and password from memory."""
 
150
        # try to get the data from the items, on keyerror create them since
 
151
        # the data is missing
 
152
        admin_username = None
 
153
        admin_password = None
 
154
        try:
 
155
            admin_username, admin_password = self.items['basic'].split(':', 1)
 
156
        except KeyError:
 
157
            admin_username = make_random_string(10)
 
158
            admin_password = make_random_string(10)
 
159
            self.items['basic'] = ':'.join([admin_username, admin_password])
 
160
        return (admin_username, admin_password) 
 
161
 
 
162
    def get_oauth_data(self):
 
163
        """Get oauth data."""
 
164
        consumer_key = make_random_string(10)
 
165
        consumer_secret = make_random_string(10)
 
166
        token = make_random_string(10)
 
167
        token_secret = make_random_string(10)
 
168
        return (consumer_key, consumer_secret, token, token_secret)
 
 
b'\\ No newline at end of file'