summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcello Stanisci <stanisci.m@gmail.com>2020-01-09 20:18:59 +0100
committerMarcello Stanisci <stanisci.m@gmail.com>2020-01-09 20:18:59 +0100
commit55addfc68f26f50425e3af84972f4d342a99939f (patch)
tree419732a851af1143f490997e46029b51d238d394
parent61609edf10f3402c5add48c4f617e2fc76c3d934 (diff)
downloadbank-55addfc68f26f50425e3af84972f4d342a99939f.tar.gz
bank-55addfc68f26f50425e3af84972f4d342a99939f.tar.bz2
bank-55addfc68f26f50425e3af84972f4d342a99939f.zip
Switching to HTTP basic authentication.
-rw-r--r--talerbank/app/tests.py67
-rw-r--r--talerbank/app/views.py32
2 files changed, 46 insertions, 53 deletions
diff --git a/talerbank/app/tests.py b/talerbank/app/tests.py
index 692577a..87d7283 100644
--- a/talerbank/app/tests.py
+++ b/talerbank/app/tests.py
@@ -23,6 +23,7 @@ import zlib
import timeit
import logging
import unittest
+import base64
from urllib.parse import unquote
from django.db import connection
from django.test import TestCase, Client
@@ -42,6 +43,12 @@ LOGGER.setLevel(logging.INFO)
logging.disable(logging.CRITICAL)
# reenable: logging.disable(logging.NOTSET)
+def make_auth_line(username, password):
+ credentials = "%s:%s" % (username, password)
+ b64enc = base64.b64encode(bytes(credentials, "utf-8"))
+ header_line = "Basic %s" % b64enc.decode()
+ return header_line
+
def clear_db():
User.objects.all().delete()
BankAccount.objects.all().delete()
@@ -259,8 +266,7 @@ class LoginTestCase(TestCase):
def test_failing_login(self):
response = self.client.get(
reverse("history", urlconf=urls), {"auth": "basic"}, **{
- "HTTP_X_TALER_BANK_USERNAME": "Wrong",
- "HTTP_X_TALER_BANK_PASSWORD": "Credentials"
+ "HTTP_AUTHORIZATION": make_auth_line("Wrong", "Credentials")
}
)
data = response.content.decode("utf-8")
@@ -316,8 +322,7 @@ class RejectTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "rejected_user",
- "HTTP_X_TALER_BANK_PASSWORD": "rejected_password"
+ "HTTP_AUTHORIZATION": make_auth_line("rejected_user", "rejected_password"),
}
)
self.assertEqual(response.status_code, 200)
@@ -332,8 +337,9 @@ class RejectTestCase(TestCase):
% (jdata["row_id"],
rejected.bankaccount.account_no),
content_type="application/json",
- **{"HTTP_X_TALER_BANK_USERNAME": "rejecting_user",
- "HTTP_X_TALER_BANK_PASSWORD": "rejecting_password"})
+ **{
+ "HTTP_AUTHORIZATION": make_auth_line("rejecting_user", "rejecting_password"),
+ })
self.assertEqual(response.status_code, 204)
@@ -366,8 +372,8 @@ class WithdrawHeadlessTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
- "HTTP_X_TALER_BANK_PASSWORD": "headless_password"
+ "HTTP_AUTHORIZATION": make_auth_line("headless_wallet", "headless_password")
+
}
)
self.assertEqual(200, response.status_code)
@@ -382,8 +388,7 @@ class WithdrawHeadlessTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
- "HTTP_X_TALER_BANK_PASSWORD": "headless_password"
+ "HTTP_AUTHORIZATION": make_auth_line("headless_wallet", "headless_password")
}
)
self.assertEqual(406, response.status_code)
@@ -399,8 +404,7 @@ class WithdrawHeadlessTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
- "HTTP_X_TALER_BANK_PASSWORD": "headless_password"
+ "HTTP_AUTHORIZATION": make_auth_line("headless_wallet", "headless_password")
}
)
self.assertEqual(200, response.status_code)
@@ -416,8 +420,7 @@ class WithdrawHeadlessTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
- "HTTP_X_TALER_BANK_PASSWORD": "headless_password"
+ "HTTP_AUTHORIZATION": make_auth_line("headless_wallet", "headless_password")
}
)
self.assertEqual(404, response.status_code)
@@ -432,8 +435,7 @@ class WithdrawHeadlessTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "headless_wallet",
- "HTTP_X_TALER_BANK_PASSWORD": "headless_password"
+ "HTTP_AUTHORIZATION": make_auth_line("headless_wallet", "headless_password")
}
)
self.assertEqual(400, response.status_code)
@@ -471,8 +473,7 @@ class AddIncomingTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "user_user",
- "HTTP_X_TALER_BANK_PASSWORD": "user_password"
+ "HTTP_AUTHORIZATION": make_auth_line("user_user", "user_password")
}
)
self.assertEqual(200, response.status_code)
@@ -485,8 +486,7 @@ class AddIncomingTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "user_user",
- "HTTP_X_TALER_BANK_PASSWORD": "user_password",
+ "HTTP_AUTHORIZATION": make_auth_line("user_user", "user_password"),
"HTTP_CONTENT_ENCODING": "deflate"
}
)
@@ -504,8 +504,7 @@ class AddIncomingTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "user_user",
- "HTTP_X_TALER_BANK_PASSWORD": "user_password"
+ "HTTP_AUTHORIZATION": make_auth_line("user_user", "user_password")
}
)
# note: a bad currency request gets 400.
@@ -525,8 +524,7 @@ class AddIncomingTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "user_user",
- "HTTP_X_TALER_BANK_PASSWORD": "user_password"
+ "HTTP_AUTHORIZATION": make_auth_line("user_user", "user_password")
}
)
self.assertEqual(406, response.status_code)
@@ -542,8 +540,7 @@ class AddIncomingTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "user_user",
- "HTTP_X_TALER_BANK_PASSWORD": "user_password"
+ "HTTP_AUTHORIZATION": make_auth_line("user_user", "user_password")
}
)
self.assertEqual(404, response.status_code)
@@ -595,8 +592,7 @@ class HistoryTestCase(TestCase):
content_type="application/json",
follow=True,
**{
- "HTTP_X_TALER_BANK_USERNAME": "User0",
- "HTTP_X_TALER_BANK_PASSWORD": "Password0"
+ "HTTP_AUTHORIZATION": make_auth_line("User0", "Password0")
}
)
@@ -657,8 +653,7 @@ class HistoryTestCase(TestCase):
response = self.client.get(
reverse("history-range", urlconf=urls), ctx.urlargs, **{
- "HTTP_X_TALER_BANK_USERNAME": "User",
- "HTTP_X_TALER_BANK_PASSWORD": "Password"
+ "HTTP_AUTHORIZATION": make_auth_line("User", "Password")
}
)
@@ -735,11 +730,9 @@ class HistoryTestCase(TestCase):
response = self.client.get(
reverse("history", urlconf=urls), ctx.urlargs, **{
- "HTTP_X_TALER_BANK_USERNAME": "User",
- "HTTP_X_TALER_BANK_PASSWORD": "Password"
+ "HTTP_AUTHORIZATION": make_auth_line("User", "Password")
}
)
-
self.assert_result(response, ctx)
@@ -759,12 +752,9 @@ class DBAmountSubtraction(TestCase):
)
user_bankaccount.amount.subtract(Amount(settings.TALER_CURRENCY, 2))
self.assertEqual(
- Amount.cmp(
- Amount(settings.TALER_CURRENCY, 1), user_bankaccount.amount
- ), 0
+ Amount.cmp(Amount(settings.TALER_CURRENCY, 1), user_bankaccount.amount), 0
)
-
class DBCustomColumnTestCase(TestCase):
def setUp(self):
BankAccount(user=User.objects.create_user(username='U')).save()
@@ -954,8 +944,7 @@ class BalanceTestCase(TestCase):
"account_number": 55
}, # unused
**{
- "HTTP_X_TALER_BANK_USERNAME": "U0",
- "HTTP_X_TALER_BANK_PASSWORD": "U0PASS"
+ "HTTP_AUTHORIZATION": make_auth_line("U0", "U0PASS")
}
)
data = response.content.decode("utf-8")
diff --git a/talerbank/app/views.py b/talerbank/app/views.py
index 33146ff..a6902be 100644
--- a/talerbank/app/views.py
+++ b/talerbank/app/views.py
@@ -25,6 +25,7 @@ import logging
import hashlib
import random
import re
+import base64
from urllib.parse import urlparse
import django.contrib.auth
import django.contrib.auth.views
@@ -626,7 +627,7 @@ def serve_public_accounts(request, name=None, page=None):
# @return FIXME.
def login_via_headers(view_func):
def _decorator(request, *args, **kwargs):
- user_account = auth_and_login(request)
+ user_account = basic_auth(request)
if not user_account:
raise LoginFailed("authentication failed")
return view_func(request, user_account, *args, **kwargs)
@@ -814,24 +815,27 @@ def serve_history(request, user_account):
return HttpResponse(status=204)
return JsonResponse(dict(data=history), status=200)
-
##
-# Helper function that authenticates a user by fetching the
-# credentials from the HTTP headers. Typically called from
-# decorators.
+# Implements the HTTP basic auth schema.
#
# @param request Django-specific HTTP request object.
# @return Django-specific "authentication object".
-def auth_and_login(request):
- """Return user instance after checking authentication
- credentials, False if errors occur"""
-
- username = request.META.get("HTTP_X_TALER_BANK_USERNAME")
- password = request.META.get("HTTP_X_TALER_BANK_PASSWORD")
- if not username or not password:
- raise LoginFailed("missing user/password")
- return django.contrib.auth.authenticate(username=username, password=password)
+def basic_auth(request):
+ auth_header = request.META.get("HTTP_AUTHORIZATION")
+
+ if not auth_header:
+ raise LoginFailed("missing Authorization header")
+ tokens = auth_header.split(" ")
+ if len(tokens) != 2:
+ raise LoginFailed("invalid Authorization header")
+
+ # decode the base64 content.
+ if tokens[0] != "Basic":
+ raise LoginFailed("Not supporting '%s' authorization method" % tokens[0])
+
+ username, password = base64.b64decode(tokens[1]).decode("utf-8").split(":")
+ return django.contrib.auth.authenticate(username=username, password=password)
##
# Serve a request of /reject (for rejecting wire transfers).