diff options
author | Sam | 2013-10-31 20:03:11 -0500 |
---|---|---|
committer | Sam | 2013-10-31 20:03:11 -0500 |
commit | 798012e2d21c48b07710660f1f1596bbaf51d2fe (patch) | |
tree | b2673e67a802ec1ebd39afde7b494ad98b4f0eb5 | |
parent | 74d803b0de60edf324b1a6ce589d12a055ef312b (diff) | |
download | genenetwork2-798012e2d21c48b07710660f1f1596bbaf51d2fe.tar.gz |
Implemented superuser and switching users for debugging purposes
-rw-r--r-- | wqflask/wqflask/model.py | 44 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/group_manager.html | 12 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/ind_user_manager.html | 33 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/user_manager.html | 9 | ||||
-rw-r--r-- | wqflask/wqflask/templates/base.html | 2 | ||||
-rw-r--r-- | wqflask/wqflask/user_manager.py | 58 |
6 files changed, 125 insertions, 33 deletions
diff --git a/wqflask/wqflask/model.py b/wqflask/wqflask/model.py index cf9e58e1..b508f18e 100644 --- a/wqflask/wqflask/model.py +++ b/wqflask/wqflask/model.py @@ -23,11 +23,11 @@ from wqflask.database import Base, init_db # Column('user_id', Integer(), ForeignKey('user.the_id')), # Column('role_id', Integer(), ForeignKey('role.the_id'))) -class Role(Base): - __tablename__ = "role" - id = Column(Unicode(36), primary_key=True, default=lambda: unicode(uuid.uuid4())) - name = Column(Unicode(80), unique=True, nullable=False) - description = Column(Unicode(255)) +#class Role(Base): +# __tablename__ = "role" +# id = Column(Unicode(36), primary_key=True, default=lambda: unicode(uuid.uuid4())) +# name = Column(Unicode(80), unique=True, nullable=False) +# description = Column(Unicode(255)) class User(Base): __tablename__ = "user" @@ -46,9 +46,13 @@ class User(Base): confirmed = Column(Text) # json detailing when they confirmed, etc. + superuser = Column(Text) # json detailing when they became a superuser, otherwise empty + # if not superuser + logins = relationship("Login", order_by="desc(Login.timestamp)", - lazy='dynamic' # Necessary for filter in login_count + lazy='dynamic', # Necessary for filter in login_count + foreign_keys="Login.user", ) user_collections = relationship("UserCollection", @@ -56,6 +60,14 @@ class User(Base): ) @property + def name_and_org(self): + """Nice shortcut for printing out who the user is""" + if self.organization: + return "{} from {}".format(self.full_name, self.organization) + else: + return self.full_name + + @property def login_count(self): return self.logins.filter_by(successful=True).count() @@ -69,6 +81,23 @@ class User(Base): return None @property + def superuser_info(self): + if self.superuser: + return json.loads(self.superuser) + else: + return None + + @property + def crowner(self): + """If made superuser, returns object of person who did the crowning""" + if self.superuser: + superuser_info = json.loads(self.superuser) + crowner = User.query.get(superuser_info['crowned_by']) + return crowner + else: + return None + + @property def most_recent_login(self): try: return self.logins[0] @@ -89,6 +118,9 @@ class Login(Base): successful = Column(Boolean(), nullable=False) # False if wrong password was entered session_id = Column(Text) # Set only if successfully logged in, otherwise should be blank + # Set to user who assumes identity if this was a login for debugging purposes by a superuser + assumed_by = Column(Unicode(36), ForeignKey('user.id')) + def __init__(self, user): self.user = user.id self.ip_address = request.remote_addr diff --git a/wqflask/wqflask/templates/admin/group_manager.html b/wqflask/wqflask/templates/admin/group_manager.html index df3eda33..ea9026a6 100644 --- a/wqflask/wqflask/templates/admin/group_manager.html +++ b/wqflask/wqflask/templates/admin/group_manager.html @@ -2,11 +2,7 @@ {% block title %}Group Manager{% endblock %} {% block content %} <!-- Start of body --> - <header class="jumbotron subhead" id="overview"> - <div class="container"> - <h1>Group Manager</h1> - </div> - </header> + {{ header("List of groups", "" )}} <div class="container"> <div class="page-header"> @@ -48,13 +44,13 @@ {% endblock %} -{% block js %} +{% block js %} <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script> <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.dataTables.min.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script> - + <script type="text/javascript" charset="utf-8"> $(document).ready( function () { console.time("Creating table"); @@ -80,4 +76,4 @@ console.timeEnd("Creating table"); }); </script> -{% endblock %}
\ No newline at end of file +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/ind_user_manager.html b/wqflask/wqflask/templates/admin/ind_user_manager.html index 03a86e63..dc24bca5 100644 --- a/wqflask/wqflask/templates/admin/ind_user_manager.html +++ b/wqflask/wqflask/templates/admin/ind_user_manager.html @@ -2,11 +2,6 @@ {% block title %}User Manager{% endblock %} {% block content %} <!-- Start of body --> - <header class="jumbotron subhead" id="overview"> - <div class="container"> - <h1>User Manager</h1> - </div> - </header> <div class="container"> <div class="page-header"> @@ -21,7 +16,7 @@ {% endif %} </div> - + {{ flash_me() }} <table class="table table-hover"> <!-- <thead> @@ -53,6 +48,25 @@ </tr> <tr> + <td>Superuser</td> + + {% if user.superuser %} + <td>Made supervisor {{ timeago(user.superuser_info['timestamp'] + "Z") }} by + {{ user.crowner.name_and_org }}. + </td> + {% else %} + <td> + <span> + <a class="btn btn-danger btn-small" href={{"/manage/make_superuser?user_id={}".format(user.id)}}> + Make Superuser + </a> + </span> + </td> + {% endif %} + </tr> + + + <tr> <td>Most recent login</td> {% if user.most_recent_login %} <td>{{ timeago(user.most_recent_login.timestamp.isoformat() + "Z") }} from {{ user.most_recent_login.ip_address }}</td> @@ -70,6 +84,13 @@ <td>Number of logins</td> <td>{{ user.login_count }}</td> </tr>--> + <tr> + <td colspan="2"> + <a class="btn btn-danger btn-small" href={{"/manage/assume_identity?user_id={}".format(user.id)}}> + Become this user for debugging + </a> + </td> + </tr> </table> diff --git a/wqflask/wqflask/templates/admin/user_manager.html b/wqflask/wqflask/templates/admin/user_manager.html index 1308ff4b..2b6c1b2b 100644 --- a/wqflask/wqflask/templates/admin/user_manager.html +++ b/wqflask/wqflask/templates/admin/user_manager.html @@ -2,11 +2,8 @@ {% block title %}User Manager{% endblock %} {% block content %} <!-- Start of body --> - <header class="jumbotron subhead" id="overview"> - <div class="container"> - <h1>User Manager</h1> - </div> - </header> + {{ header("List of users", "" )}} + <div class="container"> <div class="page-header"> @@ -20,6 +17,7 @@ <th>Organization</th> <th>Active</th> <th>Confirmed</th> + <th>Superuser</th> </tr> </thead> {% for user in users %} @@ -30,6 +28,7 @@ <td>{{ user.organization }}</td> <td>{{ 'Yes' if user.active else 'No' }}</td> <td title="{{ user.confirmed }}">{{ 'True' if user.confirmed else 'False' }}</td> + <td title="{{ user.superuser }}">{{ 'True' if user.superuser else 'False' }}</td> </tr> {% endfor %} </table> diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html index d52286f1..ea6db646 100644 --- a/wqflask/wqflask/templates/base.html +++ b/wqflask/wqflask/templates/base.html @@ -105,7 +105,7 @@ </li> <li class=""> {% if g.user_session.logged_in %} - <a id="login_out" href="/n/logout">Sign out</a> + <a id="login_out" title="Signed in as {{ g.user_session.user_ob.name_and_org }}." href="/n/logout">Sign out</a> {% else %} <a id="login_in" href="/n/login">Sign in</a> {% endif %} diff --git a/wqflask/wqflask/user_manager.py b/wqflask/wqflask/user_manager.py index 913ff231..c092771c 100644 --- a/wqflask/wqflask/user_manager.py +++ b/wqflask/wqflask/user_manager.py @@ -30,7 +30,7 @@ Redis = redis.StrictRedis() from flask import (Flask, g, render_template, url_for, request, make_response, - redirect, flash) + redirect, flash, abort) from wqflask import app @@ -357,22 +357,28 @@ def login(): if valid: - session_id_signed = successful_login(user) - flash("Thank you for logging in {}.".format(user.full_name), "alert-success") - response = make_response(redirect(url_for('index_page'))) - response.set_cookie(UserSession.cookie_name, session_id_signed) + return actual_login(user) + else: unsuccessful_login(user) flash("Invalid email-address or password. Please try again.", "alert-error") response = make_response(redirect(url_for('login'))) - return response + return response +def actual_login(user, assumed_by=None): + """The meat of the logging in process""" + session_id_signed = successful_login(user, assumed_by) + flash("Thank you for logging in {}.".format(user.full_name), "alert-success") + response = make_response(redirect(url_for('index_page'))) + response.set_cookie(UserSession.cookie_name, session_id_signed) + return response -def successful_login(user): +def successful_login(user, assumed_by=None): login_rec = model.Login(user) login_rec.successful = True login_rec.session_id = str(uuid.uuid4()) + login_rec.assumed_by = assumed_by #session_id = "session_id:{}".format(login_rec.session_id) session_id_signature = actual_hmac_creation(login_rec.session_id) session_id_signed = login_rec.session_id + ":" + session_id_signature @@ -424,23 +430,61 @@ def forgot_password_submit(): return render_template("new_security/forgot_password_step2.html", subject=ForgotPasswordEmail.subject) +@app.errorhandler(401) +def unauthorized(error): + return redirect(url_for('login')) + +def super_only(): + try: + superuser = g.user_session.user_ob.superuser + except AttributeError: + superuser = False + if not superuser: + flash("You must be a superuser to access that page.", "alert-error") + abort(401) + @app.route("/manage/users") def manage_users(): + super_only() template_vars = UsersManager() return render_template("admin/user_manager.html", **template_vars.__dict__) @app.route("/manage/user") def manage_user(): + super_only() template_vars = UserManager(request.args) return render_template("admin/ind_user_manager.html", **template_vars.__dict__) @app.route("/manage/groups") def manage_groups(): + super_only() template_vars = GroupsManager(request.args) return render_template("admin/group_manager.html", **template_vars.__dict__) +@app.route("/manage/make_superuser") +def make_superuser(): + super_only() + params = request.args + user_id = params['user_id'] + user = model.User.query.get(user_id) + superuser_info = basic_info() + superuser_info['crowned_by'] = g.user_session.user_id + user.superuser = json.dumps(superuser_info, sort_keys=True) + db_session.commit() + flash("We've made {} a superuser!".format(user.name_and_org)) + return redirect(url_for("manage_users")) + +@app.route("/manage/assume_identity") +def assume_identity(): + super_only() + params = request.args + user_id = params['user_id'] + user = model.User.query.get(user_id) + assumed_by = g.user_session.user_id + return actual_login(user, assumed_by) + @app.route("/n/register", methods=('GET', 'POST')) def register(): |