Skip to content

Commit de8033d

Browse files
committed
Fix, do not authenticate Web session when using RPC
1 parent 01c662e commit de8033d

File tree

5 files changed

+37
-41
lines changed

5 files changed

+37
-41
lines changed

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ Changelog
77

88
* Fix `context_get` arguments.
99

10+
* Do not authenticate with ``/web/session/authenticate`` when
11+
protocol is ``jsonrpc`` or ``xmlrpc``. It cannot authenticate API keys.
12+
1013
* Fix PyPI classifiers.
1114

1215
* Update documentation.

odooly.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import traceback
1818

1919
from configparser import ConfigParser
20+
from getpass import getpass
2021
from threading import current_thread
2122
from urllib.parse import urljoin, urlencode
2223
from xmlrpc.client import Fault, ServerProxy, MININT, MAXINT
@@ -583,7 +584,6 @@ def _auth(self, user, password, context):
583584
verified = password and uid
584585
# Ask for password
585586
if not password and uid is not False:
586-
from getpass import getpass
587587
if user is None:
588588
name = 'admin' if uid == SUPERUSER_ID else f'UID {uid}'
589589
else:
@@ -948,16 +948,16 @@ def upgrade_cancel(self, *modules):
948948
"""Press button ``Cancel Upgrade/Install/Uninstall``."""
949949
return self._upgrade(modules, button='cancel')
950950

951-
def session_authenticate(self, **kwargs):
951+
def session_authenticate(self, login=None, password=None):
952952
"""Create a Webclient session for current user."""
953-
auth_cached = self._cache_get('auth').get(self.uid)
953+
if not login:
954+
login = self.user.login
954955
params = {
955956
'db': self.db_name,
956-
'login': self.user and self.user.login,
957-
'password': auth_cached and auth_cached[1],
958-
**kwargs,
957+
'login': login,
958+
'password': password or getpass(f"Password for {login!r}: "),
959959
}
960-
self.session_info = self.client.web_session.authenticate(**params)
960+
self.session_info = self.client._authenticate_session(**params)
961961

962962
def session_destroy(self):
963963
"""Terminate current Webclient session."""
@@ -1115,14 +1115,18 @@ def close(self):
11151115
self._connections = []
11161116

11171117
def _authenticate(self, db, login, password):
1118-
if self.web and self.version_info > 8.0:
1119-
info = self.web_session.authenticate(db=db, login=login, password=password)
1120-
elif self.common:
1118+
if self.common:
11211119
info = {'uid': self.common.login(db, login, password)}
1120+
elif self.web and self.version_info > 8.0:
1121+
info = self._authenticate_session(db, login, password)
11221122
else:
11231123
raise Error("Cannot authenticate")
11241124
return info
11251125

1126+
def _authenticate_session(self, db, login, password):
1127+
info = self.web_session.authenticate(db=db, login=login, password=password)
1128+
return info
1129+
11261130
def _login(self, user, password=None, database=None):
11271131
"""Switch `user` and (optionally) `database`.
11281132

tests/_common.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ def OBJ(model, method, *params, **kw):
2121
kw['context'] = sample_context
2222
elif kw['context'] is None:
2323
del kw['context']
24-
extra = (params, kw) if kw else (params,)
25-
return ('object.execute_kw', sentinel.AUTH, model, method, *extra)
24+
return ('object.execute_kw', sentinel.AUTH, model, method, params) + ((kw,) if kw else ())
2625

2726

2827
class XmlRpcTestCase(TestCase):
@@ -44,8 +43,6 @@ def setUp(self):
4443

4544
self.service = self._patch_service()
4645
if self.server and self.database:
47-
if float(self.server_version) > 8.0:
48-
self._patch_http_post()
4946
# create the client
5047
self.client = odooly.Client(
5148
self.server, self.database, self.user, self.password)

tests/test_client.py

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ class TestService(XmlRpcTestCase):
4545
uid = 22
4646

4747
def _patch_service(self):
48-
self._patch_http_post()
4948
return mock.patch('odooly.ServerProxy._ServerProxy__request').start()
5049

5150
def _get_client(self):
@@ -96,8 +95,6 @@ def test_service_openerp_client(self, server_version=11.0):
9695
server = f"{self.server}/{self.protocol}"
9796
return_values = [str(server_version), ['newdb'], 1, {}]
9897
if self.protocol == 'jsonrpc':
99-
if server_version > 8.0:
100-
return_values[2:] = [{'uid': 22, 'user_context': {'lang': 'it_IT'}}]
10198
return_values = [{'result': rv} for rv in return_values]
10299
self.service.side_effect = return_values
103100
client = odooly.Client(server, 'newdb', 'usr', 'pss')
@@ -126,18 +123,15 @@ def test_service_openerp_client(self, server_version=11.0):
126123
self.assertIn('/%s|db' % self.protocol, str(client.db.get_progress))
127124

128125
if self.protocol == 'xmlrpc':
129-
expected_calls = [call('server_version', ()), call('list', ())]
130-
if server_version <= 8.0:
131-
expected_calls += [
132-
call('login', ('newdb', 'usr', 'pss')),
133-
call('execute_kw', ('newdb', 1, 'pss', 'res.users', 'context_get', ()))
134-
]
126+
expected_calls = [
127+
call('server_version', ()),
128+
call('list', ()),
129+
call('login', ('newdb', 'usr', 'pss')),
130+
call('execute_kw', ('newdb', 1, 'pss', 'res.users', 'context_get', ()))
131+
]
135132
else:
136-
# server_version, list, web_auth
137-
expected_calls = [ANY, ANY, ANY]
138-
if server_version <= 8.0:
139-
# server_version, list, login, context_get
140-
expected_calls += [ANY]
133+
# server_version, list, login, context_get
134+
expected_calls = [ANY, ANY, ANY, ANY]
141135
self.assertCalls(*expected_calls)
142136
self.assertOutput('')
143137

@@ -200,7 +194,7 @@ def test_create(self):
200194
self.assertOutput('')
201195

202196
def test_create_getpass(self):
203-
getpass = mock.patch('getpass.getpass',
197+
getpass = mock.patch('odooly.getpass',
204198
return_value='password').start()
205199
self.service.db.list.return_value = ['database']
206200
expected_calls = self.startup_calls + (
@@ -242,7 +236,7 @@ def test_create_from_config(self):
242236
env_tuple = (self.server, 'database', 'usr', None)
243237
read_config = mock.patch('odooly.read_config',
244238
return_value=env_tuple).start()
245-
getpass = mock.patch('getpass.getpass',
239+
getpass = mock.patch('odooly.getpass',
246240
return_value='password').start()
247241
self.service.db.list.return_value = ['database']
248242
expected_calls = self.startup_calls + (
@@ -363,19 +357,15 @@ def test_create_database(self):
363357
expected_calls = [
364358
call.db.create_database('abc', 'db1', False, 'en_US', 'admin'),
365359
call.db.list(),
360+
call.common.login('db1', 'admin', 'admin'),
361+
call.object.execute_kw('db1', 1, 'admin', 'res.users', 'context_get', ()),
366362
call.db.create_database('xyz', 'db2', False, 'fr_FR', 'secret'),
367363
call.db.list(),
364+
call.common.login('db2', 'admin', 'secret'),
365+
call.object.execute_kw('db2', 1, 'secret', 'res.users', 'context_get', ()),
368366
]
369-
if float(self.server_version) <= 8.0:
370-
expected_calls[2:2] = [
371-
call.common.login('db1', 'admin', 'admin'),
372-
call.object.execute_kw('db1', 1, 'admin', 'res.users', 'context_get', ()),
373-
]
374-
expected_calls[6:] = [
375-
call.common.login('db2', 'admin', 'secret'),
376-
call.object.execute_kw('db2', 1, 'secret', 'res.users', 'context_get', ()),
377-
]
378367

368+
if float(self.server_version) <= 8.0:
379369
self.assertRaises(
380370
odooly.Error, create_database, 'xyz', 'db2',
381371
user_password='secret', lang='fr_FR', login='other_login', country_code='CA',
@@ -388,6 +378,8 @@ def test_create_database(self):
388378
expected_calls += [
389379
call.db.create_database('xyz', 'db2', False, 'fr_FR', 'secret', 'other_login', 'CA'),
390380
call.db.list(),
381+
call.common.login('db2', 'other_login', 'secret'),
382+
call.object.execute_kw('db2', 1, 'secret', 'res.users', 'context_get', ()),
391383
]
392384
self.assertCalls(*expected_calls)
393385
self.assertOutput('')

tests/test_interact.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test_main(self):
3636
mock.patch('sys.argv', new=['odooly', '--env', 'demo']).start()
3737
read_config = mock.patch('odooly.read_config',
3838
return_value=env_tuple).start()
39-
getpass = mock.patch('getpass.getpass',
39+
getpass = mock.patch('odooly.getpass',
4040
return_value='password').start()
4141
self.service.db.list.return_value = ['database']
4242
self.service.common.login.side_effect = [17, 51]
@@ -107,7 +107,7 @@ def test_invalid_user_password(self):
107107
mock.patch('sys.argv', new=['odooly', '--env', 'demo']).start()
108108
mock.patch('os.environ', new={'LANG': 'fr_FR.UTF-8'}).start()
109109
mock.patch('odooly.read_config', return_value=env_tuple).start()
110-
mock.patch('getpass.getpass', return_value='x').start()
110+
mock.patch('odooly.getpass', return_value='x').start()
111111
self.service.db.list.return_value = ['database']
112112
self.service.common.login.side_effect = [17, None]
113113
self.service.object.execute_kw.side_effect = [{}, 42, {}, TypeError, 42, {}]

0 commit comments

Comments
 (0)