From 3067c1e2f00923be45e483846e5ff3b7be61bebd Mon Sep 17 00:00:00 2001 From: Timm Fitschen <timm.fitschen@ds.mpg.de> Date: Mon, 22 Oct 2018 22:15:25 +0200 Subject: [PATCH] ENH: Authenticator decodes auth tokens now. ... for better support of user-provided auth tokens. --- .../connection/authentication/interface.py | 4 +- src/caosdb/connection/utils.py | 62 ++++++++++++++++--- unittests/test_connection.py | 4 +- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/caosdb/connection/authentication/interface.py b/src/caosdb/connection/authentication/interface.py index 008933ca..8be18b57 100644 --- a/src/caosdb/connection/authentication/interface.py +++ b/src/caosdb/connection/authentication/interface.py @@ -27,7 +27,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty import logging from caosdb.connection.utils import urlencode from caosdb.connection.interface import CaosDBServerConnection -from caosdb.connection.utils import parse_auth_token +from caosdb.connection.utils import parse_auth_token, auth_token_to_cookie from caosdb.exceptions import LoginFailedException # meta class compatible with Python 2 *and* 3: @@ -146,7 +146,7 @@ class AbstractAuthenticator(ABC): ------- """ if self.auth_token is not None: - headers['Cookie'] = self.auth_token + headers['Cookie'] = auth_token_to_cookie(self.auth_token) class CredentialsAuthenticator(AbstractAuthenticator): diff --git a/src/caosdb/connection/utils.py b/src/caosdb/connection/utils.py index dfee2383..c1245a08 100644 --- a/src/caosdb/connection/utils.py +++ b/src/caosdb/connection/utils.py @@ -30,10 +30,11 @@ except ImportError: try: # pragma: no cover # python3 from urllib.parse import (urlencode as _urlencode, quote as _quote, - urlparse, urlunparse) + urlparse, urlunparse, unquote as _unquote) except ImportError: # pragma: no cover # python2 - from urllib import urlencode as _urlencode, quote as _quote + from urllib import (urlencode as _urlencode, quote as _quote, unquote as + _unquote) from urlparse import urlparse, urlunparse import re @@ -163,12 +164,59 @@ def check_python_ssl_version(hexversion): "\nPython 3 version is smaller than 3.2. It is not does not fully support SSL encryption. Please update your Python to 2.7.9 or greater, or 3.2 or greater." ) +_PATTERN = re.compile(r"^SessionToken=([^;]*);.*$") + +def unquote(string): + """unquote. + + Decode an urlencoded string into a plain text string. + """ + bts = _unquote(string) + if hasattr(bts, "decode"): + # python 2 + return bts.decode("utf-8") + return bts def parse_auth_token(cookie): + """parse_auth_token. + + Parse an auth token from a cookie. + + Parameters + ---------- + cookie : str + A cookie with an urlencoded authtoken. + + Returns + ------- + str + An auth token string. + """ auth_token = None - if cookie is not None: - try: - auth_token = re.compile(r";\s*.*$").split(cookie)[0] - except IndexError: - pass + if cookie is not None and _PATTERN.match(cookie): + auth_token = unquote(_PATTERN.split(cookie)[1]) return auth_token + +def auth_token_to_cookie(auth_token): + """auth_token_to_cookie. + + Urlencode an auth token string and format it as a cookie. + + Parameters + ---------- + auth_token : str + The plain auth token string. + + Raises + ------ + TypeError + If the auth_token was None + + Returns + ------- + str + A cookie + """ + if auth_token is None: + raise TypeError("Parameter `auth_token` was None.") + return "SessionToken=" + quote(auth_token) + ";" diff --git a/unittests/test_connection.py b/unittests/test_connection.py index fb9803c8..06838d1c 100644 --- a/unittests/test_connection.py +++ b/unittests/test_connection.py @@ -259,8 +259,8 @@ def test_missing_auth_method(): def test_missing_password(): connection = configure_connection() connection.configure(implementation=setup_two_resources, - password_method="plain", auth_token="test-auth-token") - assert connection.retrieve(["some"]).headers["Cookie"] == "test-auth-token" + password_method="plain", auth_token="[test-auth-token]") + assert connection.retrieve(["some"]).headers["Cookie"] == "SessionToken=%5Btest-auth-token%5D;" connection.configure(implementation=setup_two_resources, password_method="plain") with raises(LoginFailedException): -- GitLab