basic acl checks

This commit is contained in:
Davide Alberani 2016-06-02 16:06:12 +02:00
parent aa7250656f
commit 82432eaa04
4 changed files with 31 additions and 19 deletions

View file

@ -30,22 +30,24 @@
<thead>
<tr>
<th><strong>{{'Event' | translate}}</strong></th>
<th class="hcenter"><strong>{{'Attendees / Registered' | translate}}</strong></th>
<th><strong>{{'Delete' | translate}}</strong></th>
<th ng-if="hasPermission('event|update')" class="hcenter"><strong>{{'Attendees / Registered' | translate}}</strong></th>
<th ng-if="hasPermission('event|update')"><strong>{{'Actions' | translate}}</strong></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="event in events | splittedFilter:query | orderBy:eventsOrderProp">
<td>
<span><strong><a ui-sref="event.info({id: event._id})">{{event.title}}</a></strong></span>
<span><strong>{{event.title}}</strong></span>
<p>{{'Begins:' | translate}} {{event['begin-date'] | date:'fullDate'}} {{event['begin-time'] | date:'HH:mm'}}<br/>
{{'Ends:' | translate}} {{event['end-date'] | date:'fullDate' }} {{event['end-time'] | date:'HH:mm'}}</p>
</td>
<td class="hcenter">
<td ng-if="hasPermission('persons|read')" class="hcenter">
<p><span ng-init="attendeesNr = (event.persons | attendeesFilter).length">{{attendeesNr}}</span> / {{event.persons.length || 0}} ({{((attendeesNr / (event.persons.length || 0) * 100) || 0).toFixed()}}%)</p>
</td>
<td>
<button ng-click="remove(event._id)" type="button" class="btn btn-link fa fa-trash fa-lg"></button>
<td ng-if="hasPermission('event|update')">
<button ng-if="hasPermission('ticket|create')" ng-click="$state.go('ticket.new', {id: event._id})" class="btn btn-link fa fa-user-plus" type="button" title="{{'Register' | translate}}"></button>
<button ng-if="hasPermission('persons|update')" ng-click="$state.go('event.info', {id: event._id})" class="btn btn-link fa fa-list" type="button" title="{{'Manage attendees' | translate}}"></button>
<button ng-if="hasPermission('event|delete')" ng-click="remove(event._id)" type="button" class="btn btn-link fa fa-trash fa-lg" title="{{'Delete' | translate}}"></button>
</td>
</tr>
</tbody>

View file

@ -52,8 +52,7 @@
<div ng-if="logo.imgURL" class="navbar-brand"><a ng-if="logo.link" href="{{logo.link}}" target="_blank"><img src="{{logo.imgURL}}" /></a></div>
<ul class="nav navbar-nav">
<li ng-class="{active: isActive('/events') || isActive('/event')}"><a ui-sref="events">{{'Events' | translate}}</a></li>
<!-- li ng-if="hasPermission('persons|read')" ng-class="{active: isActive('/persons') || isActive('/person') || isActive('/import/persons')}"><a ui-sref="persons">{{'Persons' | translate}}</a></li -->
<li ng-class="{active: isActive('/persons') || isActive('/person') || isActive('/import/persons')}"><a ui-sref="persons">{{'Persons' | translate}}</a></li>
<li ng-if="hasPermission('persons|read')" ng-class="{active: isActive('/persons') || isActive('/person') || isActive('/import/persons')}"><a ui-sref="persons">{{'Persons' | translate}}</a></li>
</ul>
</div>
<div class="collapse navbar-collapse">

View file

@ -73,7 +73,6 @@ eventManApp.run(['$rootScope', '$state', '$stateParams', '$log', 'Info',
granted = true;
return;
}
}
);
return granted;

View file

@ -141,9 +141,7 @@ class BaseHandler(tornado.web.RequestHandler):
:returns: True if the user is allowed to perform the action or False
:rtype: bool
"""
user_info = self.current_user_info
if not user_info:
return False
user_info = self.current_user_info or {}
user_permissions = user_info.get('permissions') or []
global_permission = '%s|all' % permission.split('|')[0]
if 'admin|all' in user_permissions or global_permission in user_permissions or permission in user_permissions:
@ -263,11 +261,11 @@ class CollectionHandler(BaseHandler):
@gen.coroutine
@authenticated
def get(self, id_=None, resource=None, resource_id=None, **kwargs):
def get(self, id_=None, resource=None, resource_id=None, acl=True, **kwargs):
if resource:
# Handle access to sub-resources.
permission = '%s:%s|read' % (self.document, resource)
if not self.has_permission(permission):
if acl and not self.has_permission(permission):
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
method = getattr(self, 'handle_get_%s' % resource, None)
if method and callable(method):
@ -276,7 +274,7 @@ class CollectionHandler(BaseHandler):
if id_ is not None:
# read a single document
permission = '%s|read' % self.document
if not self.has_permission(permission):
if acl and not self.has_permission(permission):
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
self.write(self.db.get(self.collection, id_))
else:
@ -285,9 +283,9 @@ class CollectionHandler(BaseHandler):
# Please, never return JSON lists that are not encapsulated into an object,
# to avoid XSS vulnerabilities.
permission = '%s|read' % self.collection
if not self.has_permission(permission):
if acl and not self.has_permission(permission):
return self.build_error(status=401, message='insufficient permissions: %s' % permission)
self.write({self.collection: self.db.query(self.collection)})
self.write({self.collection: self.db.query(self.collection, self.arguments)})
@gen.coroutine
@authenticated
@ -423,6 +421,7 @@ class PersonsHandler(CollectionHandler):
document = 'person'
collection = 'persons'
object_id = 'person_id'
permissions = {}
def handle_get_events(self, id_, resource_id=None, **kwargs):
# Get a list of events attended by this person.
@ -563,6 +562,16 @@ class EventsHandler(CollectionHandler):
return ret
class TicketsHandler(CollectionHandler):
"""Handle requests for Tickets."""
document = 'ticket'
collection = 'tickets'
object_id = 'ticket_id'
permissions = {
'ticket|read': True
}
class EbCSVImportPersonsHandler(BaseHandler):
"""Importer for CSV files exported from eventbrite."""
csvRemap = {
@ -689,7 +698,7 @@ class WebSocketEventUpdatesHandler(tornado.websocket.WebSocketHandler):
try:
if self in _ws_clients.get(self._clean_url(self.request.uri), []):
_ws_clients[self._clean_url(self.request.uri)].remove(self)
except Exception, e:
except Exception as e:
logging.warn('WebSocketEventUpdatesHandler.on_close error closing websocket: %s', str(e))
@ -810,11 +819,14 @@ def run():
_ws_handler = (r"/ws/+event/+(?P<event_id>\w+)/+updates/?", WebSocketEventUpdatesHandler)
_persons_path = r"/persons/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
_events_path = r"/events/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
_tickets_path = r"/tickets/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?"
application = tornado.web.Application([
(_persons_path, PersonsHandler, init_params),
(r'/v%s%s' % (API_VERSION, _persons_path), PersonsHandler, init_params),
(_events_path, EventsHandler, init_params),
(r'/v%s%s' % (API_VERSION, _events_path), EventsHandler, init_params),
(_tickets_path, TicketsHandler, init_params),
(r'/v%s%s' % (API_VERSION, _tickets_path), TicketsHandler, init_params),
(r"/(?:index.html)?", RootHandler, init_params),
(r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params),
(r"/settings", SettingsHandler, init_params),
@ -841,7 +853,7 @@ def run():
http_server.listen(options.port, options.address)
# Also listen on options.port+1 for our local ws connection.
ws_application = tornado.web.Application([_ws_handler,], debug=options.debug)
ws_application = tornado.web.Application([_ws_handler], debug=options.debug)
ws_http_server = tornado.httpserver.HTTPServer(ws_application)
ws_http_server.listen(options.port+1, address='127.0.0.1')
logger.debug('Starting WebSocket on ws://127.0.0.1:%d', options.port+1)