login button and privileges info

This commit is contained in:
Davide Alberani 2016-05-29 11:32:57 +02:00
parent ad7cf30b02
commit cc8aecab76
2 changed files with 51 additions and 11 deletions

View file

@ -57,12 +57,17 @@
</div> </div>
<div class="collapse navbar-collapse"> <div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li ng-if="current_user"> <li ng-if="info.user.username">
<span class="btn">{{current_user}}</span> <span class="btn">{{info.user.username}}</span>
<span class="btn btn-link"> <span class="btn btn-link">
<a href="/logout"><span class="fa fa-sign-out vcenter"></span>&nbsp;{{'logout' | translate}}</a> <a href="/logout"><span class="fa fa-sign-out vcenter"></span>&nbsp;{{'logout' | translate}}</a>
</span> </span>
</li> </li>
<li ng-if="!info.user.username">
<span class="btn btn-link">
<a href="/login"><span class="fa fa-sign-in vcenter"></span>&nbsp;{{'login' | translate}}</a>
</span>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -71,6 +76,12 @@
<div class="main-header"> <div class="main-header">
</div> </div>
<!-- main error handling -->
<div ng-if="error.error" ng-class="{clearfix: true, alert: true, 'alert-danger': true}">
<div class="container">
{{error.message}}
</div>
</div>
<!-- all the magic takes place here: the content inside the next div changes accordingly to the location you're visiting --> <!-- all the magic takes place here: the content inside the next div changes accordingly to the location you're visiting -->
<div ui-view></div> <div ui-view></div>

View file

@ -52,14 +52,33 @@ def authenticated(method):
# If no authentication was required from the command line or config file. # If no authentication was required from the command line or config file.
if not self.authentication: if not self.authentication:
return method(self, *args, **kwargs) return method(self, *args, **kwargs)
# authenticated API calls gets redirected to /v1.0/[...] # unauthenticated API calls gets redirected to /v1.0/[...]
if self.is_api() and not self.current_user: if self.is_api() and not self.get_.current_user():
self.redirect('/v%s%s' % (API_VERSION, self.get_login_url())) self.redirect('/v%s%s' % (API_VERSION, self.get_login_url()))
return return
return original_wrapper(self, *args, **kwargs) return original_wrapper(self, *args, **kwargs)
return my_wrapper return my_wrapper
def requires(permissions):
if not isinstance(permissions, (list, tuple)):
permissions = [permissions]
def requires_wrapper(self, *args, **kwargs):
if 'none' in permissions:
return method(self, *args, **kwargs)
current_user = self.get_current_user()
res = self.db.query('users', {'username': current_user})
if not res:
return self.redirect('/v%s%s' % (API_VERSION, self.get_login_url()))
user = res[0]
if current_user == 'admin':
return method(self, *args, **kwargs)
if 'permissions' not in user:
return self.redirect('/v%s%s' % (API_VERSION, self.get_login_url()))
return requires_wrapper()
class BaseHandler(tornado.web.RequestHandler): class BaseHandler(tornado.web.RequestHandler):
"""Base class for request handlers.""" """Base class for request handlers."""
# A property to access the first value of each argument. # A property to access the first value of each argument.
@ -354,6 +373,7 @@ class PersonsHandler(CollectionHandler):
collection = 'persons' collection = 'persons'
object_id = 'person_id' object_id = 'person_id'
#@requires('persons-list')
def handle_get_events(self, id_, resource_id=None, **kwargs): def handle_get_events(self, id_, resource_id=None, **kwargs):
# Get a list of events attended by this person. # Get a list of events attended by this person.
# Inside the data of each event, a 'person_data' dictionary is # Inside the data of each event, a 'person_data' dictionary is
@ -363,6 +383,8 @@ class PersonsHandler(CollectionHandler):
# If resource_id is given, only the specified event is considered. # If resource_id is given, only the specified event is considered.
# #
# If the 'all' parameter is given, every event (also unattended ones) is returned. # If the 'all' parameter is given, every event (also unattended ones) is returned.
self.set_status(401)
return {'error': True, 'message': 'insufficient privileges'}
args = self.request.arguments args = self.request.arguments
query = {} query = {}
if id_ and not self.tobool(args.get('all')): if id_ and not self.tobool(args.get('all')):
@ -585,7 +607,13 @@ class InfoHandler(BaseHandler):
info = {} info = {}
current_user = self.get_current_user() current_user = self.get_current_user()
if current_user: if current_user:
info['current_user'] = current_user user_info = {}
user_info['username'] = current_user
res = self.db.query('users', {'username': current_user})
if res:
user = res[0]
user_info['privileges'] = user.get('privileges') or []
info['user'] = user_info
self.write({'info': info}) self.write({'info': info})
@ -628,8 +656,8 @@ class LoginHandler(RootHandler):
# show the login page # show the login page
if self.is_api(): if self.is_api():
self.set_status(401) self.set_status(401)
self.write({'error': 'authentication required', self.write({'error': True,
'message': 'please provide username and password'}) 'message': 'authentication required'})
else: else:
with open(self.angular_app_path + "/login.html", 'r') as fd: with open(self.angular_app_path + "/login.html", 'r') as fd:
self.write(fd.read()) self.write(fd.read())
@ -660,14 +688,14 @@ class LoginHandler(RootHandler):
logging.info('successful login for user %s' % username) logging.info('successful login for user %s' % username)
self.set_secure_cookie("user", username) self.set_secure_cookie("user", username)
if self.is_api(): if self.is_api():
self.write({'error': None, 'message': 'successful login'}) self.write({'error': False, 'message': 'successful login'})
else: else:
self.redirect('/') self.redirect('/')
return return
logging.info('login failed for user %s' % username) logging.info('login failed for user %s' % username)
if self.is_api(): if self.is_api():
self.set_status(401) self.set_status(401)
self.write({'error': 'authentication failed', 'message': 'wrong username and password'}) self.write({'error': True, 'message': 'wrong username and password'})
else: else:
self.redirect('/login?failed=1') self.redirect('/login?failed=1')
@ -701,7 +729,7 @@ def run():
help="URL to MongoDB server", type=str) help="URL to MongoDB server", type=str)
define("db_name", default='eventman', define("db_name", default='eventman',
help="Name of the MongoDB database to use", type=str) help="Name of the MongoDB database to use", type=str)
define("authentication", default=True, help="if set to false, no authentication is required") define("authentication", default=False, help="if set to true, authentication is required")
define("debug", default=False, help="run in debug mode") define("debug", default=False, help="run in debug mode")
define("config", help="read configuration file", define("config", help="read configuration file",
callback=lambda path: tornado.options.parse_config_file(path, final=False)) callback=lambda path: tornado.options.parse_config_file(path, final=False))
@ -720,7 +748,8 @@ def run():
# If not present, we store a user 'admin' with password 'eventman' into the database. # If not present, we store a user 'admin' with password 'eventman' into the database.
if not db_connector.query('users', {'username': 'admin'}): if not db_connector.query('users', {'username': 'admin'}):
db_connector.add('users', db_connector.add('users',
{'username': 'admin', 'password': utils.hash_password('eventman')}) {'username': 'admin', 'password': utils.hash_password('eventman'),
'privileges': ['admin']})
# If present, use the cookie_secret stored into the database. # If present, use the cookie_secret stored into the database.
cookie_secret = db_connector.query('settings', {'setting': 'server_cookie_secret'}) cookie_secret = db_connector.query('settings', {'setting': 'server_cookie_secret'})