summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2018-11-05 10:36:02 +0200
committerLars Wirzenius <liw@liw.fi>2018-11-05 10:36:02 +0200
commit82aa16698668375881e9edcab46965e4be3f5b83 (patch)
tree855cb8434e8cee343c1d7435337fe3af440a217f
parent782d42ef1ee0c7edb2a9cf68a24ea5ba60eca8cc (diff)
downloadmuck-poc-82aa16698668375881e9edcab46965e4be3f5b83.tar.gz
Add: owner metadata
-rw-r--r--muck/authz.py3
-rw-r--r--muck/authz_tests.py7
-rwxr-xr-xmuck_poc15
-rw-r--r--yarns/100-happy.yarn4
-rw-r--r--yarns/900-implements.yarn19
-rw-r--r--yarns/lib.py26
6 files changed, 47 insertions, 27 deletions
diff --git a/muck/authz.py b/muck/authz.py
index a9d5dda..bafd880 100644
--- a/muck/authz.py
+++ b/muck/authz.py
@@ -34,6 +34,9 @@ class AuthorizationChecker:
required_scopes = set(required_scopes)
return scopes.intersection(required_scopes) == required_scopes
+ def get_claims_from_token(self, r):
+ return self._get_token(r)
+
def _get_token(self, r):
authz = r.get_authorization()
try:
diff --git a/muck/authz_tests.py b/muck/authz_tests.py
index fffb96b..37ada26 100644
--- a/muck/authz_tests.py
+++ b/muck/authz_tests.py
@@ -52,3 +52,10 @@ class AuthorizationCheckerTests(unittest.TestCase):
def test_allows_for_acceptable_request(self):
r = self.create_request(['foo'])
self.assertTrue(self.ac.request_is_allowed(r, 'GET', ['foo']))
+
+ def test_returns_claims_from_token(self):
+ r = self.create_request(['foo'])
+ expected = {
+ 'scope': 'foo',
+ }
+ self.assertTrue(self.ac.get_claims_from_token(r), expected)
diff --git a/muck_poc b/muck_poc
index 4b19266..3da1b4a 100755
--- a/muck_poc
+++ b/muck_poc
@@ -79,23 +79,25 @@ class MuckAPI:
r = muck.Request(method=bottle.request.method)
r.add_headers(bottle.request.headers)
if self._ac.request_is_allowed(r, req_method, [req_scope]):
- return callback()
+ claims = self._ac.get_claims_from_token(r)
+ return callback(claims)
logging.error('Access denied')
return bottle.HTTPError(401)
return check_authz
- def _create_res(self):
+ def _create_res(self, claims):
res = self._get_json_body()
meta = {
'id': self._gen.new_id(),
'rev': self._gen.new_id(),
+ 'owner': claims.get('sub'),
}
create = muck.CreateChange(meta, res)
self._store.change(create)
return self._create_response(201, 'create', meta, res)
- def _update_res(self):
+ def _update_res(self, claims):
rid = self._get_resource_id()
try:
meta, _ = self._get_existing(rid)
@@ -112,7 +114,7 @@ class MuckAPI:
self._store.change(update)
return self._create_response(200, 'change', meta, res)
- def _show_res(self):
+ def _show_res(self, claims):
rid = self._get_resource_id()
try:
meta, res = self._get_existing(rid)
@@ -120,7 +122,7 @@ class MuckAPI:
return e
return self._create_response(200, 'show', meta, res)
- def _delete_res(self):
+ def _delete_res(self, claims):
rid = self._get_resource_id()
try:
meta, res = self._get_existing(rid)
@@ -130,7 +132,7 @@ class MuckAPI:
self._store.change(delete)
return self._create_response(200, 'delete', meta, res)
- def _search_res(self):
+ def _search_res(self, claims):
body = self._get_json_body()
cond = body.get('cond')
ms = self._store.get_memory_store()
@@ -174,6 +176,7 @@ class MuckAPI:
return {
'Muck-ID': meta['id'],
'Muck-Revision': meta['rev'],
+ 'Muck-Owner': meta['owner'],
}
diff --git a/yarns/100-happy.yarn b/yarns/100-happy.yarn
index 6e099ce..5a5ba32 100644
--- a/yarns/100-happy.yarn
+++ b/yarns/100-happy.yarn
@@ -21,6 +21,7 @@ Create a simple resource. Remember its id.
THEN status code is 201
THEN remember resource id as ID
THEN remember resource revision as REV1
+ THEN response has header "Muck-Owner: tomjon"
WHEN user tomjon makes request GET /status
THEN status code is 200
@@ -33,6 +34,7 @@ Retrieve the resource.
THEN response body is { "foo": "bar" }
THEN response has header "Muck-Id: ${ID}"
THEN response has header "Muck-Revision: ${REV1}"
+ THEN response has header "Muck-Owner: tomjon"
Update the resource.
@@ -54,6 +56,7 @@ Check the resource has been updated.
THEN response body is { "foo": "foobar" }
THEN response has header "Muck-Id: ${ID}"
THEN response has header "Muck-Revision: ${REV2}"
+ THEN response has header "Muck-Owner: tomjon"
Restart Muck. The resource should still exist.
@@ -63,6 +66,7 @@ Restart Muck. The resource should still exist.
THEN response body is { "foo": "foobar" }
THEN response has header "Muck-Id: ${ID}"
THEN response has header "Muck-Revision: ${REV2}"
+ THEN response has header "Muck-Owner: tomjon"
Search for the resource. First with a condition that is no longer
true.
diff --git a/yarns/900-implements.yarn b/yarns/900-implements.yarn
index 227be26..c81d1ef 100644
--- a/yarns/900-implements.yarn
+++ b/yarns/900-implements.yarn
@@ -17,22 +17,22 @@
IMPLEMENTS WHEN user (\S+) makes request POST /res with body (.*)
user = get_expanded_match()
body = get_expanded_match()
- POST('/res', {}, json.loads(body))
+ POST(user, '/res', {}, json.loads(body))
IMPLEMENTS WHEN user (\S+) makes request GET /res with header "(\S+): (.+)"
user = get_expanded_match()
header = get_expanded_match()
value = get_expanded_match()
- GET('/res', {header:value})
+ GET(user, '/res', {header:value})
IMPLEMENTS WHEN user (\S+) makes request GET /status
user = get_expanded_match()
- GET('/status', {})
+ GET(user, '/status', {})
IMPLEMENTS WHEN user (\S+) makes request GET /search with body (.+)
user = get_expanded_match()
body = json.loads(get_expanded_match())
- GET('/search', {}, body=body)
+ GET(user, '/search', {}, body=body)
IMPLEMENTS WHEN user (\S+) makes request PUT /res with header "(\S+): (.+)" and header "(\S+): (.+)" and body (.+)
user = get_expanded_match()
@@ -45,13 +45,13 @@
header1: value1,
header2: value2,
}
- PUT('/res', headers, json.loads(body))
+ PUT(user, '/res', headers, json.loads(body))
IMPLEMENTS WHEN user (\S+) makes request DELETE /res with header "(\S+): (.+)"
user = get_expanded_match()
header = get_expanded_match()
value = get_expanded_match()
- DELETE('/res', {header:value})
+ DELETE(user, '/res', {header:value})
## Checking HTTP responses
@@ -70,7 +70,12 @@
IMPLEMENTS THEN response has header "(\S+): (.+)"
name = get_next_match()
expected = get_expanded_match()
- assertEqual(get_header(name), expected)
+ actual = get_header(name)
+ print 'header:', name
+ print 'actual:', repr(actual)
+ print 'expected:', repr(expected)
+ print 'response headers:', V['response_headers']
+ assertEqual(actual, expected)
IMPLEMENTS THEN response body is (.+)
expected = get_expanded_match()
diff --git a/yarns/lib.py b/yarns/lib.py
index ee36f9f..583dff5 100644
--- a/yarns/lib.py
+++ b/yarns/lib.py
@@ -59,21 +59,18 @@ def start_muck():
subprocess.check_call(argv)
V['base_url'] = 'http://127.0.0.1:{}'.format(12765)
- V['token'] = create_test_token()
-
def stop_muck():
pid = int(read('muck.pid'))
os.kill(pid, signal.SIGTERM)
-def create_test_token():
+def create_test_token(sub):
key_filename = os.path.join(srcdir, 'test-key')
key_text = open(key_filename).read()
iss = 'test-issuer'
aud = 'test-audience'
- sub = 'test-user'
scopes = ['create', 'update', 'show', 'delete']
lifetime = 3600
@@ -95,28 +92,29 @@ def create_token(key_text, iss, aud, sub, scopes, lifetime):
return token.decode('ascii')
-def POST(path, headers, body):
- return request(requests.post, path, headers, body)
+def POST(sub, path, headers, body):
+ return request(sub, requests.post, path, headers, body)
-def PUT(path, headers, body):
- return request(requests.put, path, headers, body)
+def PUT(sub, path, headers, body):
+ return request(sub, requests.put, path, headers, body)
-def GET(path, headers, body=None):
- return request(requests.get, path, headers, body=body)
+def GET(sub, path, headers, body=None):
+ return request(sub, requests.get, path, headers, body=body)
-def DELETE(path, headers):
- return request(requests.delete, path, headers)
+def DELETE(sub, path, headers):
+ return request(sub, requests.delete, path, headers)
-def request(func, path, headers, body=None):
+def request(sub, func, path, headers, body=None):
url = '{}{}'.format(V['base_url'], path)
if 'Content-Type' not in headers:
headers['Content-Type'] = json_mime_type
if 'Authorization' not in headers:
- headers['Authorization'] = 'Bearer {}'.format(V['token'])
+ token = create_test_token(sub)
+ headers['Authorization'] = 'Bearer {}'.format(token)
if body is not None:
body = json.dumps(body)
V['request_url'] = url