This commit is contained in:
0
iris-web/source/app/blueprints/login/__init__.py
Normal file
0
iris-web/source/app/blueprints/login/__init__.py
Normal file
163
iris-web/source/app/blueprints/login/login_routes.py
Normal file
163
iris-web/source/app/blueprints/login/login_routes.py
Normal file
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
# IMPORTS ------------------------------------------------
|
||||
|
||||
from flask import Blueprint
|
||||
from flask import redirect
|
||||
from flask import render_template
|
||||
from flask import request
|
||||
from flask import session
|
||||
from flask import url_for
|
||||
from flask_login import current_user
|
||||
from flask_login import login_user
|
||||
|
||||
from app import app
|
||||
from app import bc
|
||||
from app import db
|
||||
|
||||
from app.forms import LoginForm
|
||||
from app.iris_engine.access_control.ldap_handler import ldap_authenticate
|
||||
from app.iris_engine.access_control.utils import ac_get_effective_permissions_of_user
|
||||
from app.iris_engine.utils.tracker import track_activity
|
||||
from app.models.cases import Cases
|
||||
from app.util import is_authentication_ldap
|
||||
from app.datamgmt.manage.manage_users_db import get_active_user_by_login
|
||||
|
||||
|
||||
login_blueprint = Blueprint(
|
||||
'login',
|
||||
__name__,
|
||||
template_folder='templates'
|
||||
)
|
||||
|
||||
log = app.logger
|
||||
|
||||
|
||||
# filter User out of database through username
|
||||
def _retrieve_user_by_username(username):
|
||||
user = get_active_user_by_login(username)
|
||||
if not user:
|
||||
track_activity("someone tried to log in with user '{}', which does not exist".format(username),
|
||||
ctx_less=True, display_in_ui=False)
|
||||
return user
|
||||
|
||||
|
||||
def _render_template_login(form, msg):
|
||||
organisation_name = app.config.get('ORGANISATION_NAME')
|
||||
login_banner = app.config.get('LOGIN_BANNER_TEXT')
|
||||
ptfm_contact = app.config.get('LOGIN_PTFM_CONTACT')
|
||||
|
||||
return render_template('login.html', form=form, msg=msg, organisation_name=organisation_name,
|
||||
login_banner=login_banner, ptfm_contact=ptfm_contact)
|
||||
|
||||
|
||||
def _authenticate_ldap(form, username, password, local_fallback=True):
|
||||
try:
|
||||
if ldap_authenticate(username, password) is False:
|
||||
if local_fallback is True:
|
||||
track_activity("wrong login password for user '{}' using LDAP auth - falling back to local based on settings".format(username),
|
||||
ctx_less=True, display_in_ui=False)
|
||||
|
||||
return _authenticate_password(form, username, password)
|
||||
|
||||
track_activity("wrong login password for user '{}' using LDAP auth".format(username),
|
||||
ctx_less=True, display_in_ui=False)
|
||||
return _render_template_login(form, 'Wrong credentials. Please try again.')
|
||||
|
||||
user = _retrieve_user_by_username(username)
|
||||
if not user:
|
||||
return _render_template_login(form, 'Wrong credentials. Please try again.')
|
||||
|
||||
return wrap_login_user(user)
|
||||
except Exception as e:
|
||||
log.error(e.__str__())
|
||||
return _render_template_login(form, 'LDAP authentication unavailable. Check server logs')
|
||||
|
||||
|
||||
def _authenticate_password(form, username, password):
|
||||
user = _retrieve_user_by_username(username)
|
||||
if not user or user.is_service_account:
|
||||
return _render_template_login(form, 'Wrong credentials. Please try again.')
|
||||
|
||||
if bc.check_password_hash(user.password, password):
|
||||
return wrap_login_user(user)
|
||||
|
||||
track_activity("wrong login password for user '{}' using local auth".format(username), ctx_less=True,
|
||||
display_in_ui=False)
|
||||
return _render_template_login(form, 'Wrong credentials. Please try again.')
|
||||
|
||||
|
||||
# CONTENT ------------------------------------------------
|
||||
# Authenticate user
|
||||
if app.config.get("AUTHENTICATION_TYPE") in ["local", "ldap"]:
|
||||
@login_blueprint.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
session.permanent = True
|
||||
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('index.index'))
|
||||
|
||||
form = LoginForm(request.form)
|
||||
|
||||
# check if both http method is POST and form is valid on submit
|
||||
if not form.is_submitted() and not form.validate():
|
||||
return _render_template_login(form, None)
|
||||
|
||||
# assign form data to variables
|
||||
username = request.form.get('username', '', type=str)
|
||||
password = request.form.get('password', '', type=str)
|
||||
|
||||
if is_authentication_ldap() is True:
|
||||
return _authenticate_ldap(form, username, password, app.config.get('AUTHENTICATION_LOCAL_FALLBACK'))
|
||||
|
||||
return _authenticate_password(form, username, password)
|
||||
|
||||
|
||||
def wrap_login_user(user):
|
||||
login_user(user)
|
||||
|
||||
track_activity("user '{}' successfully logged-in".format(user.user), ctx_less=True, display_in_ui=False)
|
||||
caseid = user.ctx_case
|
||||
session['permissions'] = ac_get_effective_permissions_of_user(user)
|
||||
|
||||
if caseid is None:
|
||||
case = Cases.query.order_by(Cases.case_id).first()
|
||||
user.ctx_case = case.case_id
|
||||
user.ctx_human_case = case.name
|
||||
db.session.commit()
|
||||
|
||||
session['current_case'] = {
|
||||
'case_name': user.ctx_human_case,
|
||||
'case_info': "",
|
||||
'case_id': user.ctx_case
|
||||
}
|
||||
|
||||
track_activity("user '{}' successfully logged-in".format(user), ctx_less=True, display_in_ui=False)
|
||||
|
||||
next_url = None
|
||||
if request.args.get('next'):
|
||||
next_url = request.args.get('next') if 'cid=' in request.args.get('next') else request.args.get('next') + '?cid=' + str(user.ctx_case)
|
||||
|
||||
if not next_url or urlsplit(next_url).netloc != '':
|
||||
next_url = url_for('index.index', cid=user.ctx_case)
|
||||
|
||||
return redirect(next_url)
|
73
iris-web/source/app/blueprints/login/templates/login.html
Normal file
73
iris-web/source/app/blueprints/login/templates/login.html
Normal file
@@ -0,0 +1,73 @@
|
||||
{% extends "layouts/static-default.html" %}
|
||||
{% block title %} {{ organisation_name }} Login {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
|
||||
<link rel="stylesheet" href="/static/assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/atlantis.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/login/login.css">
|
||||
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
<body class="login">
|
||||
<div class="login__wrapper row">
|
||||
<div class="login__left_part col-xs-12 col-md-8">
|
||||
<div class="login__logo">
|
||||
<img src="/static/assets/img/logo-white.png">
|
||||
</div>
|
||||
<h3 class="text-white">{{ organisation_name }}</h3>
|
||||
<span class="text-white text-center mt-4">{{ login_banner|replace('\n', '<br>')|safe }}</span>
|
||||
</div>
|
||||
<div class="login__right_part col-xs-12 col-md-4">
|
||||
<h3 class="login__form_title">Sign In</h3>
|
||||
|
||||
<form method="post" action="" class="login__form">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="login__form">
|
||||
<div class="login__form_field_container">
|
||||
<label for="username"><b>Username</b></label>
|
||||
<input id="username" name="username" type="text" class="form-control" required="">
|
||||
</div>
|
||||
<div class="login__form_field_container">
|
||||
<label for="password"><b>Password</b></label>
|
||||
<div class="login__form_input">
|
||||
<input id="password" name="password" type="password" class="form-control" required="">
|
||||
<div class="login__show_password" id="togglePassword">
|
||||
<i class="icon-eye"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if msg %}
|
||||
<div class="alert alert-danger"> <b>Error:</b> {{ msg }} </div>
|
||||
{% endif %}
|
||||
<div class="login__form_field_container">
|
||||
<button type="submit" class="btn btn-primary login__submit_button">Sign In</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="login__contact_container">
|
||||
{% if ptfm_contact %}
|
||||
<span>Don't have an account yet ?</span><br/>
|
||||
{{ ptfm_contact }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const togglePassword = document.querySelector('#togglePassword');
|
||||
const password = document.querySelector('#password');
|
||||
|
||||
togglePassword.addEventListener('click', function (e) {
|
||||
// toggle the type attribute
|
||||
const type = password.getAttribute('type') === 'password' ? 'text' : 'password';
|
||||
password.setAttribute('type', type);
|
||||
// toggle the eye / eye slash icon
|
||||
this.classList.toggle('login__show_password--disabled');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
{% endblock content %}
|
Reference in New Issue
Block a user