Exemplo n.º 1
0
def api_verify_email():
    """
    @TODO: add counter/log to track failed attempts

    :rtype: Response
    :return the success or failed in json format
    """
    if "POST" == request.method:
        token = utils.clean_str(request.form.get("tok"))
    else:
        token = utils.clean_str(request.args.get("tok"))

    if not token:
        return utils.jsonify_error({"message": "No token specified."})

    try:
        email = utils.get_email_from_token(token, app.config["SECRET_KEY"], app.config["SECRET_KEY"])
    except Exception as exc:
        # @TODO: add dedicated log type
        app.logger.error("api_verify_email: {}".format(exc.message))
        return utils.jsonify_error({"message": exc.message})

    app.logger.debug("Decoded email from token: {}".format(email))
    user = UserEntity.query.filter_by(email=email).first()

    if user is None:
        app.logger.error("Attempt to verify email with incorrect token: {}".format(token))
        return utils.jsonify_error({"message": "Sorry."})

    user = UserEntity.update(user, email_confirmed_at=datetime.today())
    app.logger.debug("Verified token {} for user {}".format(token, user.email))

    # @TODO: add dedicated log type
    LogEntity.account_modified(session["uuid"], "Verified token {} for user {}".format(token, user.email))
    return utils.jsonify_success({"message": "Email was verified for {}.".format(email)})
Exemplo n.º 2
0
def api_deactivate_account():
    """
    De-activate an user.
    @TODO: should change expiration date too?

    :rtype: Response
    :return the success or failed in json format
    """
    user_id = utils.get_safe_int(request.form.get("user_id"))
    user = UserEntity.get_by_id(user_id)
    user = UserEntity.update(user, active=False)
    LogEntity.account_modified(session["uuid"], "User deactivated: {}".format(user))
    return utils.jsonify_success({"message": "User deactivated."})
Exemplo n.º 3
0
def api_deactivate_account():
    """
    De-activate an user.
    @TODO: should change expiration date too?

    :rtype: Response
    :return the success or failed in json format
    """
    user_id = utils.get_safe_int(request.form.get('user_id'))
    user = UserEntity.get_by_id(user_id)
    user = UserEntity.update(user, active=False)
    LogEntity.account_modified(session['uuid'],
                               "User deactivated: {}".format(user))
    return utils.jsonify_success({"message": "User deactivated."})
Exemplo n.º 4
0
def api_extend_account():
    """
    Change the `User.usrAccessExpiresAt` to today's date + 180 days

    :rtype: Response
    :return the success or failed in json format
    """
    user_id = request.form.get("user_id")
    today_plus_180 = utils.get_expiration_date(180)
    user = UserEntity.get_by_id(user_id)
    user = UserEntity.update(user, access_expires_at=today_plus_180)
    # @TODO: add dedicated log type
    LogEntity.account_modified(session["uuid"], "Updated expiration date to {}. {}".format(today_plus_180, user.email))
    return utils.jsonify_success({"message": "Updated expiration date to {}".format(today_plus_180)})
Exemplo n.º 5
0
def api_expire_account():
    """
    Change the `User.usrAccessExpiresAt` to today's date and 00:00:00 time
    effectively blocking the user access.

    :rtype: Response
    :return the success or failed in json format
    """
    user_id = utils.get_safe_int(request.form.get("user_id"))
    user = UserEntity.get_by_id(user_id)
    today = datetime.today()
    today_start = datetime(today.year, today.month, today.day)
    user = UserEntity.update(user, access_expires_at=today_start)
    # @TODO: add dedicated log type
    LogEntity.account_modified(session["uuid"], "User access was expired. {}".format(user.email))
    return utils.jsonify_success({"message": "User access was expired."})
Exemplo n.º 6
0
def api_save_user():
    """ Save a new user to the database """
    email = request.form["email"]
    first = request.form["first"]
    last = request.form["last"]
    minitial = request.form["minitial"]
    roles = request.form.getlist("roles[]")

    email_exists = False
    try:
        existing_user = UserEntity.query.filter_by(email=email).one()
        email_exists = existing_user is not None
    except:
        pass

    if email_exists:
        return utils.jsonify_error({"message": "Sorry. This email is already taken."})

    # @TODO: fix hardcoded values
    # salt, hashed_pass = generate_auth(app.config['SECRET_KEY'], password)
    added_date = datetime.today()
    access_end_date = utils.get_expiration_date(180)

    user = UserEntity.create(
        email=email,
        first=first,
        last=last,
        minitial=minitial,
        added_at=added_date,
        modified_at=added_date,
        access_expires_at=access_end_date,
        password_hash="",
    )

    user_roles = []
    try:
        for role_name in roles:
            role_entity = RoleEntity.query.filter_by(name=role_name).one()
            user_roles.append(role_entity)
    except Exception as exc:
        app.logger.debug("Problem saving user: {}".format(exc))

    [user.roles.append(rol) for rol in user_roles]
    user = UserEntity.save(user)
    app.logger.debug("saved user: {}".format(user))
    LogEntity.account_created(session["uuid"], user)
    return utils.jsonify_success({"user": user.serialize()})
Exemplo n.º 7
0
def api_extend_account():
    """
    Change the `User.usrAccessExpiresAt` to today's date + 180 days

    :rtype: Response
    :return the success or failed in json format
    """
    user_id = request.form.get('user_id')
    today_plus_180 = utils.get_expiration_date(180)
    user = UserEntity.get_by_id(user_id)
    user = UserEntity.update(user, access_expires_at=today_plus_180)
    # @TODO: add dedicated log type
    LogEntity.account_modified(session['uuid'],
                               "Updated expiration date to {}. {}".format(
                                   today_plus_180, user.email))
    return utils.jsonify_success(
        {"message": "Updated expiration date to {}".format(today_plus_180)})
Exemplo n.º 8
0
def api_expire_account():
    """
    Change the `User.usrAccessExpiresAt` to today's date and 00:00:00 time
    effectively blocking the user access.

    :rtype: Response
    :return the success or failed in json format
    """
    user_id = utils.get_safe_int(request.form.get('user_id'))
    user = UserEntity.get_by_id(user_id)
    today = datetime.today()
    today_start = datetime(today.year, today.month, today.day)
    user = UserEntity.update(user, access_expires_at=today_start)
    # @TODO: add dedicated log type
    LogEntity.account_modified(session['uuid'],
                               "User access was expired. {}".format(user.email))
    return utils.jsonify_success({"message": "User access was expired."})
Exemplo n.º 9
0
def api_save_user():
    """ Save a new user to the database """
    email = request.form['email']
    first = request.form['first']
    last = request.form['last']
    minitial = request.form['minitial']
    roles = request.form.getlist('roles[]')

    email_exists = False
    try:
        existing_user = UserEntity.query.filter_by(email=email).one()
        email_exists = existing_user is not None
    except:
        pass

    if email_exists:
        return utils.jsonify_error(
            {'message': 'Sorry. This email is already taken.'})

    # @TODO: fix hardcoded values
    # salt, hashed_pass = generate_auth(app.config['SECRET_KEY'], password)
    added_date = datetime.today()
    access_end_date = utils.get_expiration_date(180)

    user = UserEntity.create(email=email,
                             first=first,
                             last=last,
                             minitial=minitial,
                             added_at=added_date,
                             modified_at=added_date,
                             access_expires_at=access_end_date,
                             password_hash="")

    user_roles = []
    try:
        for role_name in roles:
            role_entity = RoleEntity.query.filter_by(name=role_name).one()
            user_roles.append(role_entity)
    except Exception as exc:
        app.logger.debug("Problem saving user: {}".format(exc))

    [user.roles.append(rol) for rol in user_roles]
    user = UserEntity.save(user)
    app.logger.debug("saved user: {}".format(user))
    LogEntity.account_created(session['uuid'], user)
    return utils.jsonify_success({'user': user.serialize()})
Exemplo n.º 10
0
    def test_log_creation(self):
        """ Test CRUD operations """

        # LogType
        log_login = LogTypeEntity.create(type=LOG_TYPE_LOGIN, description='')
        log_logout = LogTypeEntity.create(type=LOG_TYPE_LOGOUT, description='')
        self.assertEquals(1, log_login.id)
        self.assertEquals(2, log_logout.id)

        # UserAgent
        user_agent_string = "Long text..."
        hash = compute_text_md5(user_agent_string)
        user_agent = UserAgentEntity.create(user_agent=user_agent_string,
                                            hash=hash,
                                            platform="Linux",
                                            browser="Firefox",
                                            version="latest",
                                            language="EN-US")
        # print(user_agent)
        self.assertEquals(1, user_agent.id)
        self.assertEquals("467ffa17419afeffe09bb98af4828a30", user_agent.hash)
        self.assertEquals("Linux", user_agent.platform)
        self.assertEquals("latest", user_agent.version)
        self.assertEquals("EN-US", user_agent.language)

        # WebSession
        web_session = WebSessionEntity.create(user_agent_id=user_agent.id)
        self.assertEquals(1, web_session.id)
        self.assertEquals(user_agent, web_session.user_agent)
        # print(web_session.user_agent)

        # Log
        log = LogEntity.create(type_id=log_login.id,
                               web_session_id=web_session.id,
                               date_time=datetime.now(),
                               details='just a test')
        log2 = LogEntity.create(type_id=log_logout.id,
                                web_session_id=web_session.id,
                                date_time=datetime.now(),
                                details='just a test')

        self.assertEquals(1, log.id)
        self.assertEquals(2, log2.id)
        self.assertEquals(LOG_TYPE_LOGIN, log.log_type.type)
        self.assertEquals(LOG_TYPE_LOGOUT, log2.log_type.type)
Exemplo n.º 11
0
def shibb_return():
    """
    Read the Shibboleth headers returned by the IdP after
    the user entered the username/password.
    If the `eduPersonPrincipalName` (aka Eppn) for the user matches the
    usrEmail of an active user then let the user in,
    otherwise let them see the login page.

    @see #shibb_redirect()
    """
    if current_user.is_authenticated():
        # next_page = request.args.get('next') or get_role_landing_page()
        return redirect(get_role_landing_page())

    # fresh login...
    uuid = session['uuid']
    email = request.headers['Mail']
    glid = request.headers['Glid']  # Gatorlink ID
    app.logger.debug("Checking if email: {} is registered for glid: {}"
                     .format(email, glid))
    user = UserEntity.query.filter_by(email=email).first()

    if not user:
        utils.flash_error("No such user: {}".format(email))
        LogEntity.login_error(uuid,
                              "Shibboleth user is not registered for this app")

        return redirect(url_for('index'))

    if not user.is_active():
        utils.flash_error("Inactive user: {}".format(email))
        LogEntity.login_error(uuid, 'Inactive user tried to login')
        return redirect(url_for('index'))

    if user.is_expired():
        utils.flash_error("User account for {} expired on {}"
                          .format(email, user.access_expires_at))
        LogEntity.login_error(uuid, 'Expired user tried to login')
        return redirect(url_for('index'))

    # Log it
    app.logger.info('Successful login via Shibboleth for: {}'.format(user))
    LogEntity.login(uuid, 'Successful login via Shibboleth')

    login_user(user, remember=False, force=False)

    # Tell Flask-Principal that the identity has changed
    identity_changed.send(current_app._get_current_object(),
                          identity=Identity(user.get_id()))
    next_page = get_role_landing_page()
    return redirect(next_page)
Exemplo n.º 12
0
def api_verify_email():
    """
    @TODO: add counter/log to track failed attempts

    :rtype: Response
    :return the success or failed in json format
    """
    if 'POST' == request.method:
        token = utils.clean_str(request.form.get('tok'))
    else:
        token = utils.clean_str(request.args.get('tok'))

    if not token:
        return utils.jsonify_error({'message': 'No token specified.'})

    try:
        email = utils.get_email_from_token(token,
                                           app.config["SECRET_KEY"],
                                           app.config["SECRET_KEY"])
    except Exception as exc:
        # @TODO: add dedicated log type
        app.logger.error("api_verify_email: {}".format(exc.message))
        return utils.jsonify_error({'message': exc.message})

    app.logger.debug("Decoded email from token: {}".format(email))
    user = UserEntity.query.filter_by(email=email).first()

    if user is None:
        app.logger.error("Attempt to verify email with incorrect token: {}"
                         .format(token))
        return utils.jsonify_error({'message': 'Sorry.'})

    user = UserEntity.update(user, email_confirmed_at=datetime.today())
    app.logger.debug("Verified token {} for user {}".format(token, user.email))

    # @TODO: add dedicated log type
    LogEntity.account_modified(session['uuid'],
                               "Verified token {} for user {}".format(
                                   token, user.email))
    return utils.jsonify_success(
        {"message": "Email was verified for {}.".format(email)})
Exemplo n.º 13
0
def shibb_return():
    """
    Read the Shibboleth headers returned by the IdP after
    the user entered the username/password.
    If the `eduPersonPrincipalName` (aka Eppn) for the user matches the
    usrEmail of an active user then let the user in,
    otherwise let them see the login page.

    @see #shibb_redirect()
    """
    if current_user.is_authenticated():
        # next_page = request.args.get('next') or get_role_landing_page()
        return redirect(get_role_landing_page())

    # fresh login...
    uuid = session['uuid']
    email = request.headers['Mail']
    glid = request.headers['Glid']  # Gatorlink ID
    app.logger.debug("Checking if email: {} is registered for glid: {}"
                     .format(email, glid))
    user = UserEntity.query.filter_by(email=email).first()

    if not user:
        utils.flash_error("No such user: {}".format(email))
        LogEntity.login_error(uuid,
                              "Shibboleth user is not registered for this app")

        return redirect(url_for('index'))

    if not user.is_active():
        utils.flash_error("Inactive user: {}".format(email))
        LogEntity.login_error(uuid, 'Inactive user tried to login')
        return redirect(url_for('index'))

    if user.is_expired():
        utils.flash_error("User account for {} expired on {}"
                          .format(email, user.access_expires_at))
        LogEntity.login_error(uuid, 'Expired user tried to login')
        return redirect(url_for('index'))

    # Log it
    app.logger.info('Successful login via Shibboleth for: {}'.format(user))
    LogEntity.login(uuid, 'Successful login via Shibboleth')

    login_user(user, remember=False, force=False)

    # Tell Flask-Principal that the identity has changed
    identity_changed.send(current_app._get_current_object(),
                          identity=Identity(user.get_id()))
    next_page = get_role_landing_page()
    return redirect(next_page)
Exemplo n.º 14
0
def logout():
    """ Destroy the user session and redirect to the home page

    Shib:
        https://shib.ncsu.edu/docs/logout.html
        https://wiki.shibboleth.net/confluence/display/CONCEPT/SLOIssues
    """
    # Log the logout
    if 'uuid' in session:
        LogEntity.logout(session['uuid'])

    logout_user()

    # Remove session keys set by Flask-Principal, and `uuid` key set manually
    for key in ('identity.name', 'identity.auth_type', 'uuid'):
        session.pop(key, None)

    # Tell Flask-Principal the user is anonymous
    identity_changed.send(current_app._get_current_object(),
                          identity=AnonymousIdentity())

    return redirect('/')
Exemplo n.º 15
0
def logout():
    """ Destroy the user session and redirect to the home page

    Shib:
        https://shib.ncsu.edu/docs/logout.html
        https://wiki.shibboleth.net/confluence/display/CONCEPT/SLOIssues
    """
    logout_user()

    # Remove session keys set by Flask-Principal
    for key in ('identity.name', 'identity.auth_type'):
        session.pop(key, None)

    # Tell Flask-Principal the user is anonymous
    identity_changed.send(current_app._get_current_object(),
                          identity=AnonymousIdentity())

    # Log the logout
    LogEntity.logout(session['uuid'])
    # Also pop the session id
    session.pop('uuid')
    return redirect('/')
Exemplo n.º 16
0
def api_list_logs():
    """
    Render the specified page of event logs
    @TODO: show user-specific logs for non-admins?

    :rtype: string
    :return the json list of logs
    """
    if "POST" == request.method:
        per_page = utils.get_safe_int(request.form.get("per_page"))
        page_num = utils.get_safe_int(request.form.get("page_num"))
    else:
        per_page = utils.get_safe_int(request.args.get("per_page"))
        page_num = utils.get_safe_int(request.args.get("page_num"))

    logs, total_pages = LogEntity.get_logs(per_page, page_num)

    return utils.jsonify_success(dict(list_of_events=logs, total_pages=total_pages))
Exemplo n.º 17
0
def api_list_logs():
    """
    Render the specified page of event logs
    @TODO: show user-specific logs for non-admins?

    :rtype: string
    :return the json list of logs
    """
    if 'POST' == request.method:
        per_page = utils.get_safe_int(request.form.get('per_page'))
        page_num = utils.get_safe_int(request.form.get('page_num'))
    else:
        per_page = utils.get_safe_int(request.args.get('per_page'))
        page_num = utils.get_safe_int(request.args.get('page_num'))

    logs, total_pages = LogEntity.get_logs(per_page, page_num)

    return utils.jsonify_success(
        dict(list_of_events=logs, total_pages=total_pages))
Exemplo n.º 18
0
def render_login_local():
    """ Render the login page with username/pass

    @see #index()
    @see #render_login_shib()
    """
    if current_user.is_authenticated():
        return redirect(get_role_landing_page())

    uuid = session['uuid']
    form = LoginForm(request.form)

    if request.method == 'POST' and form.validate():
        email = form.email.data.strip(
            ) if form.email.data else ""
        password = form.password.data.strip() if form.password.data else ""
        app.logger.debug("{} password: {}".format(email, password))

        app.logger.debug("Checking email: {}".format(email))
        user = UserEntity.query.filter_by(email=email).first()

        if user:
            app.logger.debug("Found user object: {}".format(user))
        else:
            utils.flash_error("No such email: {}".format(email))
            LogEntity.login(uuid, "No such email: {}".format(email))
            return redirect(url_for('index'))

        # if utils.is_valid_auth(app.config['SECRET_KEY'], auth.uathSalt,
        # password, auth.uathPassword):
        if '' == user.password_hash:
            app.logger.info('Log login event for: {}'.format(user))
            LogEntity.login(uuid, 'Successful login via email/password')
            login_user(user, remember=False, force=False)

            # Tell Flask-Principal that the identity has changed
            identity_changed.send(current_app._get_current_object(),
                                  identity=Identity(user.get_id()))
            return redirect(get_role_landing_page())
        else:
            app.logger.info('Incorrect pass for: {}'.format(user))
            LogEntity.login_error(uuid, 'Incorrect pass for: {}'.format(user))

    # When sending a GET request render the login form
    return render_template('index.html', form=form,
                           next_page=request.args.get('next'))
Exemplo n.º 19
0
def render_login_local():
    """ Render the login page with username/pass

    @see #index()
    @see #render_login_shib()
    """
    if current_user.is_authenticated():
        return redirect(get_role_landing_page())

    uuid = session['uuid']
    form = LoginForm(request.form)

    if request.method == 'POST' and form.validate():
        email = form.email.data.strip(
            ) if form.email.data else "*****@*****.**"
        password = form.password.data.strip() if form.password.data else ""
        app.logger.debug("{} password: {}".format(email, password))

        app.logger.debug("Checking email: {}".format(email))
        user = UserEntity.query.filter_by(email=email).first()

        if user:
            app.logger.debug("Found user object: {}".format(user))
        else:
            utils.flash_error("No such email: {}".format(email))
            LogEntity.login(uuid, "No such email: {}".format(email))
            return redirect(url_for('index'))

        # if utils.is_valid_auth(app.config['SECRET_KEY'], auth.uathSalt,
        # password, auth.uathPassword):
        if '' == user.password_hash:
            app.logger.info('Log login event for: {}'.format(user))
            LogEntity.login(uuid, 'Successful login via email/password')
            login_user(user, remember=False, force=False)

            # Tell Flask-Principal that the identity has changed
            identity_changed.send(current_app._get_current_object(),
                                  identity=Identity(user.get_id()))
            return redirect(get_role_landing_page())
        else:
            app.logger.info('Incorrect pass for: {}'.format(user))
            LogEntity.login_error(uuid, 'Incorrect pass for: {}'.format(user))

    # When sending a GET request render the login form
    return render_template('index.html', form=form,
                           next_page=request.args.get('next'))