def password_login(): if session.ok: session.destroy() email = request.form["email"].lower() password = request.form["password"] try: user = users.password_login("email", email, password) except users.ShouldUseRaven: return render_template("login/password-login.html", should_use_raven=True, email=email) except users.EmailNotFound: return render_template("login/password-login.html", bad_email=True, email=email) except users.BadPassword: return render_template("login/password-login.html", bad_password=True, email=email) except users.UserDisabled: return user_disabled_response() else: logger.info("logging in user %s (via password; email %s)", user["user_id"], email) session.create(user) return redirect(login_next())
def email_confirm(user_id, secret): if session.ok and user_id != session["user"]["user_id"]: session.destroy() try: users.email_confirm_check(user_id, secret, session["user"] if session.ok else None) except users.EmailAlreadyConfirmed: return render_template("login/email-confirm.html", already_confirmed=True, next=login_next()) except users.BadSecret: return render_template("login/email-confirm.html", bad_secret=True) if not session.ok and request.method == "POST": password = request.form["password"] try: user = users.password_login("user_id", user_id, password) except users.BadPassword: return render_template("login/email-confirm.html", unauthenticated=True, bad_password=True, user_id=user_id, secret=secret) else: logger.info("logging in user %s (during email confirmation)", user["user_id"]) session.create(user) if not session.ok: return render_template("login/email-confirm.html", unauthenticated=True, user_id=user_id, secret=secret) users.email_confirm(user_id) return render_template("login/email-confirm.html", confirmed=True, next=login_next())
def email_reset(user_id, secret): if session.ok: session.destroy() # technically we could race between checking and resetting, allowing # a user to reset their password twice, but that achieves nothing try: user = users.reset_password_check(user_id, secret) except users.BadSecret: logger.warning("bad email_reset link (user %s)", user_id) return render_template("login/email-reset.html", invalid=True) if request.method == "GET": return render_template("login/email-reset.html", ready=True, user_id=user_id, secret=secret, email=user["email"]) else: password = request.form["password"] password_again = request.form["password_again"] errors = {} if len(password) < 8: errors["password_short"] = True elif password != password_again: errors["password_again_bad"] = True if errors: return render_template("login/email-reset.html", user_id=user_id, secret=secret, email=user["email"], change_failed=True, **errors) else: users.reset_password(user_id, password) if not user["email_confirmed"]: # user arrived here via a link in an email, and is logged in users.email_confirm(user_id) session.create(user) return render_template("login/email-reset.html", success=True, next=login_next())
def password_signup(): if session.ok: session.destroy() email = request.form["email"].lower() email_again = request.form["email_again"].lower() password = request.form["password"] password_again = request.form["password_again"] errors = {} if email.endswith("@cam.ac.uk"): email_again = "" errors["should_use_raven"] = True elif not email_regex.match(email): email_again = "" errors["email_invalid"] = True elif email != email_again: email_again = "" errors["email_again_bad"] = True if len(password) < 8: errors["password_short"] = True elif password != password_again: errors["password_again_bad"] = True if not errors: with utils.with_savepoint("email_unique") as rollback: try: # the link advertises password signup as for alumni user = users.new_password_user(email, password, 'alumnus') except users.EmailAlreadyExists: rollback() errors["email_already_exists"] = True except users.ShouldUseRaven: errors["should_use_raven"] = True if errors: return render_template("login/password-signup.html", email=email, email_again=email_again, **errors) else: session.create(user) return redirect(login_next())
def raven_response(): if session.ok: session.destroy() try: r = raven.Response(request.args["WLS-Response"]) except ValueError as e: logger.warning("Invalid raven response: %s", e) abort(400) if r.url != url_for(".raven_response", _external=True): logger.warning("Invalid raven response: bad url") abort(400) issue_delta = (datetime.utcnow() - r.issue).total_seconds() if not -5 < issue_delta < 15: logger.warning("Invalid raven response: bad issue") return redirect(url_for(".raven_error", reason="error")) if not r.success: if r.status == ucam_webauth.STATUS_CANCELLED: return redirect(url_for(".raven_error", reason="cancelled")) else: return redirect(url_for(".raven_error", reason="error")) if "current" not in r.ptags: return redirect(url_for(".raven_error", reason="alumni")) user = users.get_raven_user(r.principal) if user is None: # end the transaction: it's safe to do so, and the lookup # operation is slow postgres.commit() try: lookup_data = lookup.get_crsid(r.principal) except lookup.LookupFailed: # lookup logs its own errors lookup_data = {} # This could happen, I guess... if lookup_data.get("person_type") == "alumnus": logger.warning("%s has current ptag but lookup yielded " "person_type=alumnus", r.principal) return redirect(url_for(".raven_error", reason="alumni")) # ensure that the .rollback() in except: doesn't destroy anything # (if we couldn't end the transaction above we could use savepoints) assert postgres.connection.get_transaction_status() == \ psycopg2.extensions.TRANSACTION_STATUS_IDLE try: user = users.new_raven_user(r.principal, r.ptags, lookup_data) except users.CRSIDAlreadyExists: logger.warning("Raced with another request to create Raven user " "for crsid %s", r.principal) postgres.connection.rollback() user = users.get_raven_user(r.principal) assert user is not None # for a disabled password user, we reject it during authentication # (in users.password_login). For Raven, we'll have to do it here. if not user["enable_login"]: return redirect(url_for(".raven_error", reason="disabled")) logger.info("logging in user %s (via Raven %s)", user["user_id"], r.principal) session.create(user) return redirect(login_next())