1
# Copyright 2009 Canonical Ltd.
3
# This file is part of desktopcouch.
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.
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.
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/>.
17
# Author: Manuel de la Pena <manuel.delapena@canonical.com>
18
"""Keyring implementation on windows."""
22
from itertools import count
24
from desktopcouch.application.util import make_random_string
27
class Keyring(object):
28
"""Implementation to be used on windows.
30
Provides the implementation of the keyring operations on windows
31
using the crypto lib and the registry key to store the info.
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
46
# pylint: enable=F0401
48
self.make_random_string = make_random_string_fn
49
self.registry = registry
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
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
71
info = self.registry.EnumValue(
79
# pylint: enable=W0702
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,
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')
96
def get_user_name_password(self):
97
"""Return the user name and passwd used to access desktopcouch."""
100
data_exists = self._registry_value_exists('basic')
101
key = self._open_registry_key()
104
secret = self.registry.QueryValueEx(key, 'basic')
105
secret = base64.b64decode(secret[0])
106
secret = self.crypto.CryptUnprotectData(secret,
108
admin_username, admin_password = secret[1].split(':', 1)
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,
120
return (admin_username, admin_password)
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',
135
secret = base64.b64encode(secret)
136
self.registry.SetValueEx(key, 'oauth', 0, self.registry.REG_SZ,
138
return (consumer_key, consumer_secret, token, token_secret)
141
class TestKeyring(object):
142
"""Keyring that will store the secrets on memory for testing reasons."""
145
"""Create a new instance of the class."""
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
155
admin_username, admin_password = self.items['basic'].split(':', 1)
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)
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'