summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2018-08-06 15:27:20 +0300
committerLars Wirzenius <liw@liw.fi>2018-08-06 15:27:20 +0300
commit09feb01bd97c4b3e372750c0f894cd65ee42d86a (patch)
treea129b1d0997e973de107b71487d8e99cb44ace58
parent5416c57cd286ab614129a398fe4d2da681ecc8f4 (diff)
downloadqvisqve-09feb01bd97c4b3e372750c0f894cd65ee42d86a.tar.gz
Fix: authorization code can only be used once
-rw-r--r--qvisqve/authz_attempt.py6
-rw-r--r--qvisqve/authz_attempt_tests.py6
-rw-r--r--qvisqve/token_router.py4
-rw-r--r--yarns/300-end-user-auth.yarn7
4 files changed, 22 insertions, 1 deletions
diff --git a/qvisqve/authz_attempt.py b/qvisqve/authz_attempt.py
index 229c802..21d9be5 100644
--- a/qvisqve/authz_attempt.py
+++ b/qvisqve/authz_attempt.py
@@ -107,6 +107,12 @@ class AuthorizationAttempts:
self._attempts.append(aa)
return aa
+ def delete_by_id(self, attempt_id):
+ self._attempts = [
+ aa for aa in self._attempts
+ if aa.get_attempt_id() != attempt_id
+ ]
+
def find_by_id(self, attempt_id):
for aa in self._attempts:
if aa.get_attempt_id() == attempt_id:
diff --git a/qvisqve/authz_attempt_tests.py b/qvisqve/authz_attempt_tests.py
index d46660d..a9fadb6 100644
--- a/qvisqve/authz_attempt_tests.py
+++ b/qvisqve/authz_attempt_tests.py
@@ -90,6 +90,12 @@ class AuthorizationAttemptsTests(unittest.TestCase):
self.assertEqual(aa.get_state(), self.urlparams['state'])
self.assertEqual(aa.get_redirect_uri(), self.urlparams['redirect_uri'])
+ def test_deletes_attempt(self):
+ aa = self.aas.create_attempt(self.urlparams)
+ attempt_id = aa.get_attempt_id()
+ self.aas.delete_by_id(attempt_id)
+ self.assertEqual(self.aas.find_by_id(attempt_id), None)
+
def test_finds_by_id(self):
aa = self.aas.create_attempt(self.urlparams)
attempt_id = aa.get_attempt_id()
diff --git a/qvisqve/token_router.py b/qvisqve/token_router.py
index c510b8b..ea37065 100644
--- a/qvisqve/token_router.py
+++ b/qvisqve/token_router.py
@@ -137,7 +137,7 @@ class AuthorizationCodeGrant(Grant):
aa = self._attempts.find_by_code(code)
if aa is None:
qvisqve.log.log('error', msg_text='Unknown code given', code=code)
- return qvisqve.unauthorized_response('Access denied')
+ return qvisqve.bad_request_response('Bad request')
subject_id = aa.get_subject_id()
scope = aa.get_scope()
@@ -148,6 +148,8 @@ class AuthorizationCodeGrant(Grant):
if s in allowed
)
+ self._attempts.delete_by_id(aa.get_attempt_id())
+
empty_token = self._generator.new_token(
'', scope, subject_id=subject_id)
return qvisqve.ok_response({
diff --git a/yarns/300-end-user-auth.yarn b/yarns/300-end-user-auth.yarn
index e69ccad..da79b03 100644
--- a/yarns/300-end-user-auth.yarn
+++ b/yarns/300-end-user-auth.yarn
@@ -181,4 +181,11 @@ this. Needs research and thinking.
AND access token has a scope field set to read
AND access token has a sub field set to tomjon
+The authorization code can't be re-used.
+
+ WHEN facade requests POST /token, with
+ ... form values grant_type=authorization_code and code=${CODE}
+ ... using Basic Auth with username facade, password happydays
+ THEN HTTP status code is 400 Bad request
+
FINALLY Qvisqve is stopped