Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
Refusing permission to an anonymous request¶
This document reproduces a unicode error that occurred when Lino tried to say “As Anonymous you have no permission to run this action.” in German (where the internationalized text contains non-ascii characters.
The error was:
UnicodeEncodeError at /api/trading/InvoicesByJournal
'ascii' codec can't encode character u'\xfc' in position 64: ordinal not in range(128)
Preliminary tests¶
This document uses lino_book.projects.cosi1
:
>>> print(settings.SETTINGS_MODULE)
lino_book.projects.cosi1.settings
>>> print(settings.SITE.default_user)
None
>>> print(settings.SITE.user_model)
<class 'lino.modlib.users.models.User'>
>>> print(settings.SITE.remote_user_header)
None
>>> print(settings.SITE.get_auth_method())
session
>>> print('\n'.join(settings.MIDDLEWARE))
django.middleware.common.CommonMiddleware
django.middleware.locale.LocaleMiddleware
django.contrib.sessions.middleware.SessionMiddleware
lino.core.auth.middleware.AuthenticationMiddleware
lino.core.auth.middleware.WithUserMiddleware
>>> 'django.contrib.sessions' in settings.INSTALLED_APPS
True
Value of mt in the following snippets must be … >>> contenttypes.ContentType.objects.get_for_model(accounting.Journal).id 23
Here we go¶
An end user signs in…
>>> test_client.force_login(rt.login('robin').user)
… and then uses the main menu to open
lino_xl.lib.trading.InvoicesByJournal
, which will do the following AJAX
call to get its data:
>>> url = '/api/trading/InvoicesByJournal'
>>> url += "?start=0&limit=25&fmt=json&rp=ext-comp-1135"
>>> url += "&pv=1&pv=&pv=&pv=&pv=&mt=23&mk=1"
>>> res = test_client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
>>> res.status_code
200
>>> r = json.loads(res.content.decode())
>>> print(json.dumps(sorted(r.keys())))
["count", "html_text", "no_data_text", "param_values", "rows", "success", "title"]
>>> len(r['rows'])
25
After seeing this data the user gets a coffee break and leaves their browser open. The server administrator meanwhile does a dump and a reload of the database. So the sessions have been removed. We simulate this:
>>> x = sessions.Session.objects.all().delete()
The user comes back and resizes their browser window, or some other action that triggers a refresh. The browser will issue the same URL, but it will now return a 403 (Forbidden) response:
>>> import logging
>>> logger = logging.getLogger("django.request")
>>> logger.setLevel(logging.CRITICAL)
>>> res = test_client.get(url)
>>> res.status_code
403
>>> print(res.content.decode().strip())
<!doctype html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<h1>403 Forbidden</h1><p></p>
</body>
</html>
Lino no longer treats exceptions during an AJAX call specially.
Before 20240921, when an exception like the above occurred during an AJAX call,
Lino’s response had a different format, which is defined by the
lino.utils.ajax
middleware. Lino recognized AJAX calls by the extra HTTP
header HTTP_X_REQUESTED_WITH having the value XMLHttpRequest
, which we
must say explicitly to Django’s test client.
>>> res = test_client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
Result is now exactly the same as without HTTP_X_REQUESTED_WITH:
>>> res.status_code
403
>>> print(res.content.decode().strip())
<!doctype html>
<html lang="en">
<head>
<title>403 Forbidden</title>
</head>
<body>
<h1>403 Forbidden</h1><p></p>
</body>
</html>