Cookie consent plugin breaking login in backend
Problem Description
The JS cookieconsent plugin we use sets cookies of form
cc_cookie:"{"level":["necessary"],"revision":0}"
which can't be properly parsed by backend dependencies. This causes logins to fail.
In particular, login sessions rely on the repoze.who
package processing the auth_tkt
cookie value for authentication. The cookie is parsed via the get_cookies
function imported from the paste.request
module of the paste
package.
This get_cookies
function is implemented using the python standard library import
from Cookie import SimpleCookie
followed by
cookies = SimpleCookie()
...
cookies.load(header)
which behaves differently across python 2.7.x versions.
In case of an HTTP request containing both an authentication token and cookie consent settings:
"GET / HTTP/1.0"
Referer: http://opsi-vagrant.local/
Cookie: cc_cookie={"level":["necessary"],"revision":0}; auth_tkt="c219e91ae4b3c788bbfd009b3a9cef65640fba591%3DOPSI_VAGRANT_LOCAL%2C2%3Durn%253Aoasis%253Anames%253Atc%253ASAML%253A2.0%253Anameid-format%253Atransient%2C4%3D_0d55e7ce0f7e13b9a626c2e4036411c9b9aeb2a3b5!"; auth_tkt="c219e91ae4b3c788bbfd009b3a9cef65640fba591%3DOPSI_VAGRANT_LOCAL%2C2%3Durn%253Aoasis%253Anames%253Atc%253ASAML%253A2.0%253Anameid-format%253Atransient%2C4%3D_0d55e7ce0f7e13b9a626c2e4036411c9b9aeb2a3b5!"
On the opsi-dev server running python 2.7.5
, the cookie gets parsed as
<SimpleCookie: auth_tkt='c219e91ae4b3c788bbfd009b3a9cef65640fba591%3DOPSI_VAGRANT_LOCAL%2C2%3Durn%253Aoasis%253Anames%253Atc%253ASAML%253A2.0%253Anameid-format%253Atransient%2C4%3D_0d55e7ce0f7e13b9a626c2e4036411c9b9aeb2a3b5!' cc_cookie='{'>
(note how cc_cookie
is improperly parsed),
whereas on latest python 2.7.18
, parsing it returns a completely empty dictionary:
<SimpleCookie: >
Because of this, login sessions cannot be persisted, and although the user initially logs in successfully, no access is available to functionality that requires login.
Workaround
The problem can be worked around by filtering the cc_cookie
key-value pair out of the HTTP Cookie header at the NginX reverse proxy entry point via regex matches:
server {
...
location / {
set $altered_cookie $http_cookie;
if ($http_cookie ~ '(.*)(^|;\s)cc_cookie=("[^"]*"|[^\s]*[^;]?)(\2|$|;$)(?:;\s)?(.*)') {
set $altered_cookie $1$4$5;
}
proxy_hide_header Cookie;
proxy_set_header Cookie $altered_cookie;
proxy_pass http://127.0.0.1:8080/;
...
}
But this introduces unnecessary regex computations for every HTTP request.
Proposed Solution
The proper solution is to use cookie values that can be properly parsed by the Cookie
module in Python 2.7.18's standard library. It seems that this can be done by upgrading cookieconsent
to a newer version:
Release 2.6.0 of cookieconsent
introduces an option to use rfc_compliant cookies, and release 2.6.1 improves on the implementation.
Moreover, cookieconsent
is available as the npm package vanilla-cookieconsent. Therefore it best to remove the various unnecessary files belonging to the cookieconsent
repository from our codebase, install vanilla-cookieconsent
as an npm package with a fixed version, and simply import in our configuration in ckanext-dgu/ckanext/dgu/theme/src/sass/js/cookieconsent/src/cookieconsent-opsi.js
.