コード例 #1
0
def report():
    """
    This method provides a facility for users to report authentication
    interactions which they consider suspicious. The results are logged and
    emailed to a configurable address.
    """
    if request.method == 'GET':
        rep_auth, all_auths = None, None
        if 'auth_id' in request.args:
            rep_auth_id = request.args['auth_id']
            if not rep_auth_id.isdigit() and int(rep_auth_id) < 0:
                raise Exception(
                    'non-positive integer auth_id provided to report method')
            rep_auth = Verification.by_id(rep_auth_id)
        if rep_auth is None:
            all_auths = Verification.all(session['username'])
        response = render_template('report.html',
                                   auth=rep_auth,
                                   all_auths=all_auths)
    else:
        reason = request.form['reason']
        report = request.form['reported_auth_id']
        log.info(u"user {user} reported authentication with "
                 u"id '{report}' as suspicious with reason: {reason}".format(
                     user=session['username'],
                     report=report,
                     reason=re.sub(r'[\n\r]+', ' ', reason)))
        email_report(reason, session['username'], report)
        response = render_template('report-submitted.html')
    db.done(True)
    return response
コード例 #2
0
def search():
    """
    The method displays a search form (GET) and searches the staff
    directory for a user (POST) and returns the results to the user. The
    initial implmentation uses LDAP as the staff directory server.
    """
    if request.method == 'POST':
        search = request.form['searchstr'].strip()
        if len(search) > 2 and re.match(r'^[a-zA-Z0-9\s]+\Z', search):
            staff = config.directory.module.Directory()
            res = staff.search(search)
            log.debug(u"user {user} searched for string '{search}', which "
                      u"matched {count} directory record(s)".format(
                          user=session['username'],
                          search=search,
                          count=len(res)))
        else:
            log.info(
                u"user {user} searched for illegal string '{search}'".format(
                    user=session['username'], search=search))
            res = []
            search = ''
            flash(u"Search words must be longer than 2 "
                  u"characters and only contain alpha-numeric " +
                  u"characters (0-9a-zA-Z) and white space")
        return render_template(
            'search.html',
            search=search,
            results=res,
            attribute_names=config.directory.attribute_names)
    else:
        return render_template('search.html')
コード例 #3
0
def authenticate():
    """
    A form handler which creates an authentication for the existing user
    (determined via the 'username' term of session) to another user
    (accepted as a form input variable). On success, it returns a page,
    showing the user details of the newly created authentication.

    It has several logic checks, which may cause and error (or abort):

    * The source and destination uid are not identical.
    * The authentication doesn't already exist, that is, a non-expired
      authentication with the same source and destination is not already
      present.
    * There is also a check (within the authentication code) that will
      cause and exception if the destination is not within the staff
      directory. This should only occur if the client is tampering with
      the request variables, not through valid use of this app.

    """
    # The following conversions to have been implemented as a
    # workaround to the limitations in the python-ldap library
    # which appears to not correctly handle UTF8
    src = session['username'].encode('ascii', 'ignore')
    if 'authselect' in request.form:
        dst = request.form['authselect'].encode('ascii', 'ignore')
    else:
        flash(u"No user selected to authenticate.")
        return go_home()
    if src == dst:
        log.debug(u'Illegal authenication attempted with identical '
                  u'source ({src}) and destination ({dst})'.format(src=src,
                                                                   dst=dst))
        flash(u"You can't authenticate yourself.")
        return go_home()
    if Verification.exists(src, dst):
        log.debug(u'Duplicate authentication attempted with '
                  u'source ({src}) and destination ({dst})'.format(src=src,
                                                                   dst=dst))
        flash("Authentication already exists.")
        return go_home()
    log.info(u'Authentication created by {src} for {dst} from {ip}'.format(
        src=src, dst=dst, ip=request.remote_addr))
    try:
        verification = Verification(src, dst)
        db.session.add(verification)  # pylint: disable=E1101
    except Exception:
        log.error("Authentication creation error: {trace}".format(
            trace=format_exc()))
        db.done(False)
        flash('Failed to create authentication! Please try again later.')
        return go_home()
    response = make_response(render_template('auth.html', auth=verification))
    db.done(True)
    response.headers['Refresh'] = ('{refresh}; {url}'.format(
        refresh=config.application.refresh, url=url_for('index')))
    return response
コード例 #4
0
def logout():
    """
    Log out from the application which de-authenticates the session then
    redirects back to the index page.

    Attempts to go to the logout page without already having logged in will
    redirect to /login
    """
    if 'username' in session:
        session['logged_in'] = False
        log.info(
            u"Logout of user {user}.".format(user=session.pop('username')))
        flash('You have been logged out')
    return go_home()
コード例 #5
0
def check_authentication():
    # Don't interfere with unauthenticated routes
    if (request.endpoint is None
            or request.endpoint in app.unauthenticated_routes):
        return
    if 'username' not in session or not session.get('logged_in', False):
        log.debug(u"{endpoint} requested without a valid session. "
                  u"Redirecting to login.".format(endpoint=request.endpoint))
        return redirect(url_for('login'))
    elif session.get('timeout', 0.0) < time.time():
        session['logged_in'] = False
        flash('Your session has expired, please login again.')
        log.info(u'Session expired for user {user}.'.format(
            user=session['username']))
        return redirect(url_for('login'))
コード例 #6
0
def email_report(text, reporter_uid, auth):
    """
    A email a report of a suspicious authentication interaction.
    The destination email address, from address, subject and mail server is
    read from a configuration file.

    :param text: the text of the report
    :param reporter_uid: the uid (user id) of the reporter
    :param auth: the authentication id (a uniquely identifying int)
    """
    msg = MIMEText(_message_body.format(
        time=str(datetime.utcnow()),
        reporter=reporter_uid,
        auth=str(Verification.by_id(auth)),
        report=text
    ))
    msg['Subject'] = config.report.email_subject
    msg['To'] = ', '.join(config.report.email_to)
    msg['From'] = config.report.email_from
    try:
        s = smtplib.SMTP(config.report.smtp_server)
        s.sendmail(
            config.report.email_from,
            config.report.email_to,
            msg.as_string()
        )
        s.quit()
        log.info(
            'Emailed suspicious interaction '
            'report {src} to {dst} via {server}'.format(
                src=config.report.email_from,
                dst=', '.join(config.report.email_to),
                server=config.report.smtp_server
            )
        )
    except Exception:
        log.error('Failed to send suspicious interaction report via email.')
        raise
コード例 #7
0
def login():
    """
    A form (GET) and the assocaited handler (POST) for validation of user
    credentials.

    It is possible to put the application in testing mode, so that password
    checks are not enforced and the user only need supply a username. This
    should never be enabled in production. (See also: check_password and
    use_radius :doc:`configuration` options.)

    Otherwise, the users authentication credentials will be authenticated
    using the configured authentication module.
    """
    auth = config.login.module.Authentication
    if request.method == 'GET' and session.get('logged_in', False):
        # Login attempt while logged in - just redirect home
        return go_home()
    elif request.method == 'POST':
        session['timeout'] = time.time() + config.application.session_timeout
        session['username'], session['logged_in'] = auth.authenticate(
            request.form)
        if session['logged_in']:
            log.info("Authentication successful ({type}) for "
                     "user {user} from {ip}".format(type=config.login.type,
                                                    user=session['username'],
                                                    ip=request.remote_addr))
            flash("Welcome {user}.".format(user=session['username']))
            return go_home()
        else:
            log.info("Authentication failure ({type}) for "
                     "user {user} from {ip}".format(type=config.login.type,
                                                    user=session['username'],
                                                    ip=request.remote_addr))
            flash("Login failed.")
    return render_template('login.html',
                           inputs=auth.template_inputs(),
                           warning=not auth.for_production())