Ejemplo n.º 1
0
def load_user_from_request(request):
    """
	Load user object via access token

	Access token may be supplied via a GET parameter or the Authorization
	HTTP header.

	:param request:  Flask request
	:return:  User object, or None if no valid access token was given
	"""
    token = request.args.get("access-token")

    if not token:
        token = request.headers.get("Authorization")

    if not token:
        return None

    user = db.fetchone(
        "SELECT name AS user FROM access_tokens WHERE token = %s AND (expires = 0 OR expires > %s)",
        (token, int(time.time())))
    if not user:
        return None
    else:
        db.execute(
            "UPDATE access_tokens SET calls = calls + 1 WHERE name = %s",
            (user["user"], ))
        user = User.get_by_name(user["user"])
        user.authenticate()
        return user
Ejemplo n.º 2
0
def show_login():
    """
	Handle logging in

	If not submitting a form, show form; if submitting, check if login is valid
	or not.

	:return: Redirect to either the URL form, or the index (if logged in)
	"""
    if current_user.is_authenticated:
        return redirect(url_for("show_index"))

    if request.method == 'GET':
        return render_template('account/login.html',
                               flashes=get_flashed_messages())

    username = request.form['username']
    password = request.form['password']
    registered_user = User.get_by_login(username, password)

    if registered_user is None:
        flash('Username or Password is invalid.', 'error')
        return redirect(url_for('show_login'))

    login_user(registered_user, remember=True)

    return redirect(url_for("show_index"))
Ejemplo n.º 3
0
def reset_password():
    """
	Reset a password

	This page requires a valid reset token to be supplied as a GET parameter.
	If that is satisfied then the user may choose a new password which they can
	then use to log in.
	"""
    if current_user.is_authenticated:
        # this makes no sense if you're already logged in
        return render_template(
            "error.html",
            message=
            "You are already logged in and cannot request another account.")

    token = request.args.get("token", None) or request.form.get("token", None)
    if token is None:
        # we need *a* token
        return render_template(
            "error.html",
            message="You need a valid reset token to set a password.")

    resetting_user = User.get_by_token(token)
    if not resetting_user or resetting_user.is_special():
        # this doesn't mean the token is unknown, but it could be older than 3 days
        return render_template(
            "error.html",
            message=
            "You need a valid reset token to set a password. Your token may have expired: in this case, you have to request a new one."
        )

    # check form
    incomplete = []
    if request.method == "POST":
        # check password validity
        password = request.form.get("password", None)
        if password is None or len(password) < 8:
            incomplete.append("password")
            flash("Please provide a password of at least 8 characters.")

        # reset password if okay and redirect to login
        if not incomplete:
            resetting_user.set_password(password)
            resetting_user.clear_token()
            flash("Your password has been set. You can now log in to 4CAT.")
            return redirect(url_for("show_login"))

    # show form
    return render_template("account/reset-password.html",
                           username=resetting_user.get_name(),
                           incomplete=incomplete,
                           flashes=get_flashed_messages(),
                           token=token,
                           form=request.form)
Ejemplo n.º 4
0
def load_user(user_name):
    """
	Load user object

	Required for Flask-Login.
	:param user_name:  ID of user
	:return:  User object
	"""
    user = User.get_by_name(user_name)
    if user:
        user.authenticate()
    return user
Ejemplo n.º 5
0
def autologin_whitelist():
    """
	Checks if host name matches whitelisted hostmask. If so, the user is logged
	in as the special "autologin" user.
	"""
    if not config.FlaskConfig.HOSTNAME_WHITELIST:
        # if there's not whitelist, there's no point in checking it
        return

    if "/static/" in request.path:
        # never check login for static files
        return

    try:
        socket.setdefaulttimeout(2)
        hostname = socket.gethostbyaddr(request.remote_addr)[0]
    except (socket.herror, socket.timeout):
        return

    if current_user:
        if current_user.get_id() == "autologin":
            # whitelist should be checked on every request
            logout_user()
        elif current_user.is_authenticated:
            # if we're logged in as a regular user, no need for a check
            return

    # uva is a special user that is automatically logged in for this request only
    # if the hostname matches the whitelist
    for hostmask in config.FlaskConfig.HOSTNAME_WHITELIST:
        if fnmatch.filter([hostname], hostmask):
            autologin_user = User.get_by_name("autologin")
            if not autologin_user:
                # this user should exist by default
                abort(500)
            autologin_user.authenticate()
            login_user(autologin_user, remember=False)
Ejemplo n.º 6
0
def add_user():
	if not current_user.is_admin():
		return error(403, message="This page is off-limits to you.")

	response = {"success": False}

	email = request.form.get("email", request.args.get("email", "")).strip()

	if not email or not re.match(r"[^@]+\@.*?\.[a-zA-Z]+", email):
		response = {**response, **{"message": "Please provide a valid e-mail address."}}
	else:
		username = email
		try:
			db.insert("users", data={"name": username, "timestamp_token": int(time.time())})

			user = User.get_by_name(username)
			if user is None:
				response = {**response, **{"message": "User was created but could not be instantiated properly."}}
			else:
				try:
					user.email_token(new=True)
					response["success"] = True
					response = {**response, **{
						"message": "An e-mail containing a link through which the registration can be completed has been sent to %s." % username}}
				except RuntimeError as e:
					response = {**response, **{
						"message": "User was created but the registration e-mail could not be sent to them (%s)." % e}}
		except psycopg2.IntegrityError:
			db.rollback()
			response = {**response, **{"message": "Error: User %s already exists." % username}}

	if request.args.get("format", None) == "html":
		return render_template("error.html", message=response["message"],
							   title=("New account created" if response["success"] else "Error"))
	else:
		return jsonify(response)
Ejemplo n.º 7
0
args = cli.parse_args()

if __name__ != "__main__":
	sys.exit(1)

if not re.match(r"[^@]+\@.*?\.[a-zA-Z]+", args.username):
	print("Please provide an e-mail address as username.")
	sys.exit(1)

try:
	db.insert("users", data={"name": args.username, "timestamp_token": int(time.time())})
except psycopg2.IntegrityError:
	print("Error: User %s already exists." % args.username)
	sys.exit(1)

user = User.get_by_name(args.username)
if user is None:
	print("Warning: User not created properly. No password reset e-mail sent.")
	sys.exit(1)

try:
	user.email_token(new=True)
	print("An e-mail containing a link through which the registration can be completed has been sent to %s." % args.username)
except RuntimeError as e:
	print("""
WARNING: User registered but no e-mail was sent. The following exception was raised:
   %s
   
%s can complete their registration via the following token:
   %s""" % (e, args.username, user.get_token()))
Ejemplo n.º 8
0
def add_user():
    """
	Create a new user

	Sends the user an e-mail with a link through which they can set their
	password.

	:return: Either an html page with a message, or a JSON response, depending
	on whether ?format == html
	"""
    if not current_user.is_authenticated or not current_user.is_admin():
        return error(403, message="This page is off-limits to you.")

    response = {"success": False}

    email = request.form.get("email", request.args.get("email", "")).strip()
    fmt = request.form.get("format", request.args.get("format", "")).strip()
    force = request.form.get("force", request.args.get("force", None))

    if not email or not re.match(r"[^@]+\@.*?\.[a-zA-Z]+", email):
        response = {
            **response,
            **{
                "message": "Please provide a valid e-mail address."
            }
        }
    else:
        username = email
        try:
            db.insert("users",
                      data={
                          "name": username,
                          "timestamp_token": int(time.time())
                      })

            user = User.get_by_name(username)
            if user is None:
                response = {
                    **response,
                    **{
                        "message":
                        "User was created but could not be instantiated properly."
                    }
                }
            else:
                try:
                    user.email_token(new=True)
                    response["success"] = True
                    response = {
                        **response,
                        **{
                            "message":
                            "An e-mail containing a link through which the registration can be completed has been sent to %s." % username
                        }
                    }
                except RuntimeError as e:
                    response = {
                        **response,
                        **{
                            "message":
                            "User was created but the registration e-mail could not be sent to them (%s)." % e
                        }
                    }
        except psycopg2.IntegrityError:
            db.rollback()
            if not force:
                response = {
                    **response,
                    **{
                        "message":
                        'Error: User %s already exists. If you want to re-create the user and re-send the registration e-mail, use [this link](/admin/add-user?email=%s&force=1&format=%s).' % (username, username, fmt)
                    }
                }
            else:
                # if a user does not use their token in time, maybe you want to
                # be a benevolent admin and give them another change, without
                # having them go through the whole signup again
                user = User.get_by_name(username)
                db.update("users",
                          data={"timestamp_token": int(time.time())},
                          where={"name": username})

                try:
                    user.email_token(new=True)
                    response["success"] = True
                    response = {
                        **response,
                        **{
                            "message":
                            "A new registration e-mail has been sent to %s." % username
                        }
                    }
                except RuntimeError as e:
                    response = {
                        **response,
                        **{
                            "message":
                            "Token was reset registration e-mail could not be sent to them (%s)." % e
                        }
                    }

    if fmt == "html":
        return render_template(
            "error.html",
            message=response["message"],
            title=("New account created" if response["success"] else "Error"))
    else:
        return jsonify(response)
Ejemplo n.º 9
0
def request_password():
    """
	Request a password reset

	A user that is not logged in can use this page to request that a password
	reset link will be sent to them. Only one link can be requested per 3 days.

	This view is rate-limited to prevent brute forcing a list of e-mails.
	:return:
	"""
    if current_user.is_authenticated:
        # using this while logged in makes no sense
        return render_template(
            "error.html",
            message=
            "You are already logged in and cannot request a password reset.")

    # check form submission
    incomplete = []
    if request.method == "POST":
        # we need *a* username
        username = request.form.get("username", None)
        if username is None:
            incomplete.append(username)
            flash("Please provide a username.")

        # is it also a valid username? that is not a 'special' user (like autologin)?
        resetting_user = User.get_by_name(username)
        if resetting_user is None or resetting_user.is_special():
            incomplete.append("username")
            flash(
                "That user is not known here. Note that your username is typically your e-mail address."
            )

        elif resetting_user.get_token() and resetting_user.data[
                "timestamp_token"] > 0 and resetting_user.data[
                    "timestamp_token"] > time.time() - (3 * 86400):
            # and have they not already requested a reset?
            incomplete.append("")
            flash(
                "You have recently requested a password reset and an e-mail has been sent to you containing a reset link. It could take a while to arrive; also, don't forget to check your spam folder."
            )
        else:
            # okay, send an e-mail
            try:
                resetting_user.email_token(new=False)
                return render_template(
                    "error.html",
                    title="Success",
                    message=
                    "An e-mail has been sent to you containing instructions on how to reset your password."
                )
            except RuntimeError:
                # no e-mail could be sent - clear the token so the user can try again later
                resetting_user.clear_token()
                incomplete.append(username)
                flash(
                    "The username was recognised but no reset e-mail could be sent. Please try again later."
                )

    # show page
    return render_template("account/request-password.html",
                           incomplete=incomplete,
                           flashes=get_flashed_messages(),
                           form=request.form)