Skip to content
Snippets Groups Projects
Commit a9666f4c authored by Gunnar Schaefer's avatar Gunnar Schaefer
Browse files

refactor User PUT based on json payload

parent 4c305543
No related branches found
No related tags found
No related merge requests found
......@@ -36,7 +36,7 @@ class Acquisitions(base.RequestHandler):
projection = {'label': 1, 'description': 1, 'types': 1, 'notes': 1}
if self.public_request:
query['public'] = True
elif not self.superuser:
elif not self.superuser_request:
query['permissions'] = {'$elemMatch': {'uid': self.uid, 'site': self.source_site}}
projection['permissions'] = {'$elemMatch': {'uid': self.uid, 'site': self.source_site}}
acquisitions = list(self.dbc.find(query, projection))
......
......@@ -38,6 +38,13 @@ ROLES = [
INTEGER_ROLES = {r['rid']: r['sort'] for r in ROLES}
def mongo_dict(d):
def _mongo_list(d, pk=''):
pk = pk and pk + '.'
return sum([_mongo_list(v, pk+k) if isinstance(v, dict) else [(pk+k, v)] for k, v in d.iteritems()], [])
return dict(_mongo_list(d))
class RequestHandler(webapp2.RequestHandler):
"""fetches pubkey from own self.db.remotes. needs to be aware of OWN site uid"""
......@@ -112,11 +119,13 @@ class RequestHandler(webapp2.RequestHandler):
if not self.app.db.remotes.find_one({'_id': remote_instance}):
self.abort(402, remote_instance + ' is not authorized')
self.public_request = not bool(self.uid)
if not self.public_request:
user = self.app.db.users.find_one({'_id': self.uid}, ['superuser'])
if self.public_request or self.source_site:
self.superuser_request = False
else:
user = self.app.db.users.find_one({'_id': self.uid}, ['root', 'wheel'])
if not user:
self.abort(403, 'user ' + self.uid + ' does not exist')
self.superuser = not self.public_request and not self.source_site and user.get('superuser')
self.superuser_request = user.get('root') and user.get('wheel')
def dispatch(self):
"""dispatching and request forwarding"""
......@@ -161,9 +170,12 @@ class RequestHandler(webapp2.RequestHandler):
headers['Access-Control-Allow-Origin'] = self.response.headers['Access-Control-Allow-Origin']
webapp2.abort(code, *args, **kwargs)
def handle_exception(self, exception, debug):
self.abort(500, exception.message)
def options(self, *args, **kwargs):
self.response.headers['Access-Control-Allow-Methods'] = 'GET, HEAD, POST, PUT, DELETE, OPTIONS'
self.response.headers['Access-Control-Allow-Headers'] = 'Authorization'
self.response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type'
self.response.headers['Access-Control-Max-Age'] = '151200'
def schema(self, updates={}):
......@@ -182,7 +194,7 @@ class Container(RequestHandler):
if not container.get('public', False):
self.abort(403, 'this ' + self.__class__.__name__ + 'is not public')
del container['permissions']
elif not self.superuser:
elif not self.superuser_request:
user_perm = None
for perm in container['permissions']:
if perm['uid'] == self.uid and perm.get('site') == self.source_site:
......@@ -200,7 +212,7 @@ class Container(RequestHandler):
class AcquisitionAccessChecker(object):
def check_acq_list(self, acq_ids):
if not self.superuser:
if not self.superuser_request:
for a_id in acq_ids:
agg_res = self.app.db.acquisitions.aggregate([
{'$match': {'_id': a_id}},
......
......@@ -17,7 +17,7 @@
"email": "user1@example.com",
"firstname": "First",
"lastname": "User",
"superuser": true
"wheel": true
}
]
}
......@@ -31,7 +31,7 @@ class Projects(base.RequestHandler):
query = None
if self.public_request:
query = {'public': True}
elif not self.superuser:
elif not self.superuser_request:
projection['permissions'] = {'$elemMatch': {'uid': self.uid, 'site': self.source_site}}
if self.request.get('admin').lower() in ('1', 'true'):
query = {'permissions': {'$elemMatch': {'uid': self.uid, 'site': self.source_site, 'access': 'admin'}}}
......
......@@ -36,7 +36,7 @@ class Sessions(base.RequestHandler):
projection = {'label': 1, 'subject.code': 1, 'notes': 1}
if self.public_request:
query['public'] = True
elif not self.superuser:
elif not self.superuser_request:
query['permissions'] = {'$elemMatch': {'uid': self.uid, 'site': self.source_site}}
projection['permissions'] = {'$elemMatch': {'uid': self.uid, 'site': self.source_site}}
sessions = list(self.dbc.find(query, projection))
......
......@@ -28,14 +28,12 @@ class Users(base.RequestHandler):
"""Create a new User"""
if self.public_request: # FIXME: who is allowed to create a new user?
self.abort(403, 'must be logged in to create new user')
schema = copy.deepcopy(User.json_schema)
schema['required'] += ['email', 'firstname', 'lastname']
json_body = self.request.json_body
try:
jsonschema.validate(json_body, schema)
json_body = self.request.json_body
jsonschema.validate(json_body, User.json_schema)
json_body['email_hash'] = hashlib.md5(json_body['email']).hexdigest()
self.dbc.insert(json_body)
except jsonschema.ValidationError as e:
except (ValueError, jsonschema.ValidationError) as e:
self.abort(400, str(e))
except pymongo.errors.DuplicateKeyError as e:
self.abort(400, 'User ID %s already exists' % json_body['_id'])
......@@ -44,7 +42,7 @@ class Users(base.RequestHandler):
"""Return the list of Users."""
if self.public_request:
self.abort(403, 'must be logged in to retrieve User list')
users = list(self.dbc.find({}, ['firstname', 'lastname', 'email_hash', 'superuser']))
users = list(self.dbc.find({}, ['firstname', 'lastname', 'email_hash', 'wheel']))
if self.debug:
for user in users:
user['details'] = self.uri_for('user', _id=str(user['_id']), _full=True) + '?' + self.request.query_string
......@@ -80,8 +78,12 @@ class User(base.RequestHandler):
'email_hash': {
'type': 'string',
},
'superuser': {
'title': 'Superuser',
'root': {
'title': 'Root',
'type': 'boolean',
},
'wheel': {
'title': 'Wheel',
'type': 'boolean',
},
'preferences': {
......@@ -95,7 +97,7 @@ class User(base.RequestHandler):
},
},
},
'required': ['_id'],
'required': ['_id', 'email', 'firstname', 'lastname'],
'additionalProperties': False,
}
......@@ -105,7 +107,9 @@ class User(base.RequestHandler):
def self(self):
"""Return details for the current User."""
return self.dbc.find_one({'_id': self.uid}, ['firstname', 'lastname', 'superuser', 'preferences'])
user = self.dbc.find_one({'_id': self.uid}, ['firstname', 'lastname', 'root', 'wheel', 'preferences', 'email_hash'])
user.setdefault('preferences', {})
return user
def get(self, _id):
""" Return User details."""
......@@ -119,7 +123,7 @@ class User(base.RequestHandler):
user = self.dbc.find_one({'_id': _id}, projection or None)
if not user:
self.abort(404, 'no such User')
if self.debug and (self.superuser or _id == self.uid):
if self.debug and (self.superuser_request or _id == self.uid):
user['groups'] = self.uri_for('groups', _id=_id, _full=True) + '?' + self.request.query_string
return user
......@@ -127,26 +131,23 @@ class User(base.RequestHandler):
"""Update an existing User."""
user = self.dbc.find_one({'_id': _id})
if not user:
self.abort(404)
if _id == self.uid or self.superuser: # users can only update their own info
updates = {'$set': {'_id': _id}, '$unset': {'__null__': ''}}
for k, v in self.request.params.iteritems():
if k != 'superuser' and k in []:#user_fields:
updates['$set'][k] = v # FIXME: do appropriate type conversion
elif k == 'superuser' and _id == self.uid and self.superuser is not None: # toggle superuser for requesting user
updates['$set'][k] = v.lower() in ('1', 'true')
elif k == 'superuser' and _id != self.uid and self.superuser: # enable/disable superuser for other user
if v.lower() in ('1', 'true') and user.get('superuser') is None:
updates['$set'][k] = False # superuser is tri-state: False indicates granted, but disabled, superuser privileges
elif v.lower() not in ('1', 'true'):
updates['$unset'][k] = ''
self.dbc.update({'_id': _id}, updates)
else:
self.abort(403)
self.abort(404, 'no such User')
if not self.superuser_request and _id != self.uid:
self.abort(403, 'must be superuser to update another User')
schema = copy.deepcopy(self.json_schema)
del schema['required']
try:
json_body = self.request.json_body
jsonschema.validate(json_body, schema)
except (ValueError, jsonschema.ValidationError) as e:
self.abort(400, str(e))
if 'wheel' in json_body and _id == self.uid:
self.abort(400, 'user cannot alter own superuser privilege')
self.dbc.update({'_id': _id}, {'$set': base.mongo_dict(json_body)})
def delete(self, _id):
"""Delete a User."""
if not self.superuser:
if not self.superuser_request:
self.abort(403, 'must be superuser to delete a User')
self.dbc.remove({'_id': _id})
......@@ -167,11 +168,11 @@ class Groups(base.RequestHandler):
"""Return the list of Groups."""
query = None
if _id is not None:
if _id != self.uid and not self.superuser:
if _id != self.uid and not self.superuser_request:
self.abort(403, 'User ' + self.uid + ' may not see the Groups of User ' + _id)
query = {'roles.uid': _id}
else:
if not self.superuser:
if not self.superuser_request:
if self.request.get('admin').lower() in ('1', 'true'):
query = {'roles': {'$elemMatch': {'uid': self.uid, 'access': 'admin'}}}
else:
......@@ -228,7 +229,7 @@ class Group(base.RequestHandler):
group = self.app.db.groups.find_one({'_id': _id})
if not group:
self.abort(404, 'no such Group: ' + _id)
if not self.superuser:
if not self.superuser_request:
group = self.app.db.groups.find_one({'_id': _id, 'roles': {'$elemMatch': {'uid': self.uid, 'access': 'admin'}}})
if not group:
self.abort(403, 'User ' + self.uid + ' is not an admin of Group ' + _id)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment