Skip to content

Commit

Permalink
[FIX] base_import_module, cli: deploy
Browse files Browse the repository at this point in the history
The use of the `deploy` command always fails because of an incorrect
CSRF token since commit 9bae56a. Indeed, the latter
re-introduces the session rotation, i.e. the session ID is changed at
authentication.

Practically, what happens server-side is:
- authentication
- generate CSRF token
- create the response with the token and a change of session ID

At this point, the token generated is not correct anymore since it is
based on the 'old' session ID. Therefore, when it is reused at
uploading, an error is raised.

It is actually possible to simplify the process by performing the
authentication and the file upload in a single request. There is indeed
no real use of extracting the authentication, since the request is then
only used to upload the module.

opw-1902863

closes odoo#28653
  • Loading branch information
nim-odoo committed Nov 14, 2018
1 parent 4df0a1e commit 79d29c5
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 37 deletions.
16 changes: 4 additions & 12 deletions addons/base_import_module/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,14 @@ def check_user(self, uid=None):
if not is_admin:
raise AccessError(_("Only administrators can upload a module"))

@route('/base_import_module/login', type='http', auth='none', methods=['POST'], csrf=False)
@route(
'/base_import_module/login_upload',
type='http', auth='none', methods=['POST'], csrf=False, save_session=False)
@webservice
def login(self, login, password, db=None):
def login_upload(self, login, password, db=None, force='', mod_file=None, **kw):
if db and db != request.db:
raise Exception(_("Could not select database '%s'") % db)
uid = request.session.authenticate(request.db, login, password)
if not uid:
return Response(response="Wrong login/password", status=401)
self.check_user(uid)
return Response(headers={
'X-CSRF-TOKEN': request.csrf_token(),
})

@route('/base_import_module/upload', type='http', auth='user', methods=['POST'])
@webservice
def upload(self, mod_file=None, force='', **kw):
self.check_user()
force = True if force == '1' else False
return request.env['ir.module.module'].import_zipfile(mod_file, force=force)[0]
39 changes: 14 additions & 25 deletions odoo/cli/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,29 @@ def __init__(self):

def deploy_module(self, module_path, url, login, password, db='', force=False):
url = url.rstrip('/')
csrf_token = self.authenticate(url, login, password, db)
module_file = self.zip_module(module_path)
try:
return self.upload_module(url, module_file, force=force, csrf_token=csrf_token)
return self.login_upload_module(module_file, url, login, password, db, force=force)
finally:
os.remove(module_file)

def upload_module(self, server, module_file, force=False, csrf_token=None):
def login_upload_module(self, module_file, url, login, password, db, force=False):
print("Uploading module file...")
url = server + '/base_import_module/upload'

post_data = {'force': '1' if force else ''}
if csrf_token: post_data['csrf_token'] = csrf_token

endpoint = url + '/base_import_module/login_upload'
post_data = {
'login': login,
'password': password,
'db': db,
'force': '1' if force else '',
}
with open(module_file, 'rb') as f:
res = self.session.post(url, files={'mod_file': f}, data=post_data)
res.raise_for_status()

return res.text
res = self.session.post(endpoint, files={'mod_file': f}, data=post_data)

def authenticate(self, server, login, password, db=''):
print("Authenticating on server '%s' ..." % server)

# Fixate session with a given db if any
self.session.get(server + '/web/login', params=dict(db=db))

args = dict(login=login, password=password, db=db)
res = self.session.post(server + '/base_import_module/login', args)
if res.status_code == 404:
raise Exception("The server '%s' does not have the 'base_import_module' installed." % server)
elif res.status_code != 200:
raise Exception(res.text)

return res.headers.get('x-csrf-token')
raise Exception(
"The server '%s' does not have the 'base_import_module' installed or is not up-to-date." % url)
res.raise_for_status()
return res.text

def zip_module(self, path):
path = os.path.abspath(path)
Expand Down

0 comments on commit 79d29c5

Please sign in to comment.