Add support for basic authentication for user application
Closes #14528
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Add support for basic authentication for user application
|
||||
* Support the conversion of MJML reports to HTML
|
||||
* Allow filtering users to be notified by cron tasks
|
||||
|
||||
|
||||
@@ -52,8 +52,9 @@ creation of such route.
|
||||
|
||||
``user_application(name[, json])``
|
||||
Set the :attr:`~trytond.transaction.Transaction.user` from the
|
||||
``Authorization`` header using the type ``bearer`` and a valid key for the
|
||||
named user application.
|
||||
``Authorization`` header using the ``bearer`` type with the user application
|
||||
key, or the ``basic`` type without a username and with the user application
|
||||
key as the password.
|
||||
|
||||
User Application Key
|
||||
====================
|
||||
|
||||
@@ -292,13 +292,17 @@ def user_application(name, json=True):
|
||||
authorization = parse_authorization_header(header)
|
||||
if authorization is None:
|
||||
abort(HTTPStatus.UNAUTHORIZED)
|
||||
if authorization.type != 'bearer':
|
||||
abort(HTTPStatus.FORBIDDEN)
|
||||
|
||||
token = getattr(authorization, 'token', '')
|
||||
if authorization.type == 'bearer':
|
||||
token = getattr(authorization, 'token', '')
|
||||
elif authorization.type == 'basic':
|
||||
token = authorization.get('password')
|
||||
else:
|
||||
abort(HTTPStatus.UNAUTHORIZED)
|
||||
|
||||
application = UserApplication.check(token, name)
|
||||
if not application:
|
||||
abort(HTTPStatus.FORBIDDEN)
|
||||
abort(HTTPStatus.UNAUTHORIZED)
|
||||
transaction = Transaction()
|
||||
# TODO language
|
||||
with transaction.set_user(application.user.id), \
|
||||
|
||||
@@ -3,12 +3,17 @@
|
||||
|
||||
import datetime
|
||||
import json
|
||||
from base64 import b64encode
|
||||
from decimal import Decimal
|
||||
|
||||
from trytond.pool import Pool
|
||||
from trytond.protocols.jsonrpc import JSONDecoder, JSONEncoder, JSONRequest
|
||||
from trytond.protocols.wrappers import (
|
||||
HTTPStatus, Response, user_application, with_pool, with_transaction)
|
||||
from trytond.protocols.xmlrpc import XMLRequest, client
|
||||
from trytond.tests.test_tryton import TestCase
|
||||
from trytond.tests.test_tryton import Client, RouteTestCase, TestCase
|
||||
from trytond.tools.immutabledict import ImmutableDict
|
||||
from trytond.wsgi import TrytondWSGI
|
||||
|
||||
|
||||
def _identity(x):
|
||||
@@ -130,3 +135,82 @@ class XMLTestCase(DumpsLoadsMixin, TestCase):
|
||||
result, _ = client.loads(s)
|
||||
result, = result
|
||||
self.assertEqual(result, Decimal('3.141592653589793'))
|
||||
|
||||
|
||||
class UserApplication(RouteTestCase):
|
||||
module = 'res'
|
||||
|
||||
@classmethod
|
||||
def setUpDatabase(cls):
|
||||
pool = Pool()
|
||||
User = pool.get('res.user')
|
||||
UserApplication = pool.get('res.user.application')
|
||||
|
||||
UserApplication.application.selection.append(('test', "Test"))
|
||||
|
||||
User.create([{
|
||||
'login': 'user',
|
||||
'applications': [('create', [{
|
||||
'key': 'secret_key',
|
||||
'application': 'test',
|
||||
'state': 'validated',
|
||||
}])],
|
||||
}])
|
||||
|
||||
def test_authorization_bearer(self):
|
||||
app = TrytondWSGI()
|
||||
test_application = user_application('test')
|
||||
|
||||
@app.route('/<database_name>/test/user_application')
|
||||
@with_pool
|
||||
@with_transaction()
|
||||
@test_application
|
||||
def _route(request, pool):
|
||||
return ''
|
||||
|
||||
client = Client(app, Response)
|
||||
response = client.get(
|
||||
f'/{self.db_name}/test/user_application',
|
||||
headers=[
|
||||
('Authorization', 'bearer secret_key'),
|
||||
])
|
||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||
|
||||
def test_authorization_basic(self):
|
||||
app = TrytondWSGI()
|
||||
test_application = user_application('test')
|
||||
|
||||
@app.route('/<database_name>/test/user_application')
|
||||
@with_pool
|
||||
@with_transaction()
|
||||
@test_application
|
||||
def _route(request, pool):
|
||||
return ''
|
||||
|
||||
client = Client(app, Response)
|
||||
auth = b64encode(b':secret_key').decode('ascii')
|
||||
response = client.get(
|
||||
f'/{self.db_name}/test/user_application',
|
||||
headers=[
|
||||
('Authorization', f'basic {auth}'),
|
||||
])
|
||||
self.assertEqual(response.status_code, HTTPStatus.OK)
|
||||
|
||||
def test_authorization_bad_auth(self):
|
||||
app = TrytondWSGI()
|
||||
test_application = user_application('test')
|
||||
|
||||
@app.route('/<database_name>/test/user_application')
|
||||
@with_pool
|
||||
@with_transaction()
|
||||
@test_application
|
||||
def _route(request, pool):
|
||||
return ''
|
||||
|
||||
client = Client(app, Response)
|
||||
response = client.get(
|
||||
f'/{self.db_name}/test/user_application',
|
||||
headers=[
|
||||
('Authorization', 'bearer foo'),
|
||||
])
|
||||
self.assertEqual(response.status_code, HTTPStatus.UNAUTHORIZED)
|
||||
|
||||
Reference in New Issue
Block a user