Skip to content

Commit 4470bd3

Browse files
committed
issue2551050 document mechanism to allow uers limited access to
privileged info that can be accessed by expansion of a template. Example used was searching the user's roles property for a Developer role.
1 parent f2dc1b1 commit 4470bd3

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

doc/rest.txt

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,115 @@ returns some data about the class::
12111211
Adding other endpoints (e.g. to allow an OPTIONS query against
12121212
``/data/issue/@schema``) is left as an exercise for the reader.
12131213

1214+
Controlling Access to Backend Data
1215+
==================================
1216+
1217+
Roundup's schema is the primary access control mechanism. Roles and
1218+
Permissions provide the ability to carefully control what data can be
1219+
seen.
1220+
1221+
However the templating system can access the hyperdb directly which
1222+
allows filtering to happen with admin privs escaping the standard
1223+
permissions scheme. For example access to a user's roles should be
1224+
limited to the user (read only) and an admin. If you have customized
1225+
your schema to implement `Restricting the list of
1226+
users that are assignable to a task <customizing.html#restricting-the-list-of-users-that-are-assignable-to-a-task>`__ so that only users with a
1227+
Developer role are allowed to be assigned to an issue, a rest end
1228+
point must be added to provide a view that exposes users with this
1229+
permission.
1230+
1231+
Using the normal ``/data/user?roles=Developer`` will return all the
1232+
users in the system unless you are an admin user because most users
1233+
can't see the roles. Building on the `Adding new rest endpoints`_
1234+
section this code adds a new endpoint `/data/@permission/Developer`
1235+
that returns a list of users with the developer role::
1236+
1237+
from roundup.rest import Routing, RestfulInstance
1238+
from cgi import MiniFieldStorage
1239+
1240+
class RestfulInstance(object):
1241+
1242+
@Routing.route("/data/@permission/Developer")
1243+
def get_role_Developer(self, input):
1244+
'''An endpoint to return a list of users with Developer
1245+
role who can be assigned to an issue.
1246+
1247+
It ignores attempt to search by any property except
1248+
username and realname. It also ignores the whole @fields
1249+
specification if it specifies a property the user
1250+
can't view. Other @ query params (e.g. @page... and
1251+
@verbose) are supported.
1252+
1253+
It assumes admin access rights so that the roles property
1254+
of the user can be searched. This is needed if the roles
1255+
property is not searchable/viewable by normal users. A user
1256+
who can search roles can identify users with the admin
1257+
role. So it does not respond the same as a rest/data/users
1258+
search by a non-admin user.
1259+
'''
1260+
# get real user id
1261+
realuid=self.db.getuid()
1262+
1263+
def allowed_field(fs):
1264+
if fs.name in ['username', 'realname' ]:
1265+
# only allow search matches for these fields
1266+
return True
1267+
elif fs.name in [ '@fields' ]:
1268+
for prop in fs.value.split(','):
1269+
# if any property is unviewable to user, remove
1270+
# @field entry. If they can't see it for the admin
1271+
# user, don't let them see it for any user.
1272+
if not self.db.security.hasPermission(
1273+
'View', realuid, 'user', property=prop,
1274+
itemid='1'):
1275+
return False
1276+
return True
1277+
elif fs.name.startswith("@"):
1278+
# allow @page..., @verbose etc.
1279+
return True
1280+
1281+
# deny all other url parmeters
1282+
return False
1283+
1284+
# Cleanup input.list to prevent user from probing roles
1285+
# or viewing things the user should not be able to view.
1286+
input.list[:] = [ fs for fs in input.list
1287+
if allowed_field(fs) ]
1288+
1289+
# Add the role filter required to implement the permission
1290+
# search
1291+
input.list.append(MiniFieldStorage("roles", "Developer"))
1292+
1293+
# change user to acquire permission to search roles
1294+
self.db.setCurrentUser('admin')
1295+
1296+
# Once we have cleaned up the request, pass it to
1297+
# get_collection as though /rest/data/users?... has been called
1298+
# to get @verbose and other args supported.
1299+
return self.get_collection('user', input)
1300+
1301+
Calling this with: `curl 'http://example.com/demo/rest/data/@permission/Developer?@fields=realname&roles=Users&@verbose=2'`
1302+
produces output similar to::
1303+
1304+
{
1305+
"data": {
1306+
"collection": [
1307+
{
1308+
"username": "agent",
1309+
"link": http://example.com/demo/rest/data/user/4",
1310+
"realname": "James Bond",
1311+
"id": "4"
1312+
}
1313+
],
1314+
"@total_size": 1
1315+
}
1316+
}
1317+
1318+
assuming user 4 is the only user with the Developer role. Note that
1319+
the url passes the `roles=User` filter option which is silently
1320+
ignored.
1321+
1322+
12141323
Creating Custom Rate Limits
12151324
===========================
12161325

0 commit comments

Comments
 (0)