summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ogcp/cfg/ogcp.json2
-rw-r--r--ogcp/forms/auth.py20
-rw-r--r--ogcp/models.py5
-rw-r--r--ogcp/templates/auth/login.html12
-rw-r--r--ogcp/templates/base.html2
-rw-r--r--ogcp/templates/nav.html18
-rw-r--r--ogcp/views.py57
-rw-r--r--requirements.txt1
8 files changed, 117 insertions, 0 deletions
diff --git a/ogcp/cfg/ogcp.json b/ogcp/cfg/ogcp.json
index 9e715d4..cff1cad 100644
--- a/ogcp/cfg/ogcp.json
+++ b/ogcp/cfg/ogcp.json
@@ -2,4 +2,6 @@
"IP": "127.0.0.1",
"PORT": 8888,
"API_TOKEN": "c3fe7bb0395747ec42a25df027585871"
+ "USER": "user",
+ "PASS": "pass"
}
diff --git a/ogcp/forms/auth.py b/ogcp/forms/auth.py
new file mode 100644
index 0000000..8c84e84
--- /dev/null
+++ b/ogcp/forms/auth.py
@@ -0,0 +1,20 @@
+from wtforms import (
+ Form, SubmitField, HiddenField, SelectField, BooleanField, IntegerField,
+ StringField, RadioField, PasswordField
+)
+from wtforms.validators import InputRequired
+from flask_wtf import FlaskForm
+from flask_babel import _
+
+class LoginForm(FlaskForm):
+ user = StringField(
+ label=_('User'),
+ validators=[InputRequired()]
+ )
+ pwd = PasswordField(
+ label=_('Password'),
+ validators=[InputRequired()]
+ )
+ submit = SubmitField(
+ label=_('Login')
+ )
diff --git a/ogcp/models.py b/ogcp/models.py
new file mode 100644
index 0000000..668c623
--- /dev/null
+++ b/ogcp/models.py
@@ -0,0 +1,5 @@
+from flask_login import UserMixin
+
+class User(UserMixin):
+ def get_id(self):
+ return 1
diff --git a/ogcp/templates/auth/login.html b/ogcp/templates/auth/login.html
new file mode 100644
index 0000000..220f69e
--- /dev/null
+++ b/ogcp/templates/auth/login.html
@@ -0,0 +1,12 @@
+{% extends 'base.html' %}
+{% import "bootstrap/wtf.html" as wtf %}
+
+{% block content %}
+
+{{ wtf.quick_form(form,
+ method='post',
+ form_type='basic',
+ button_map={'submit':'primary'},
+ extra_classes='p-5') }}
+
+{% endblock %}
diff --git a/ogcp/templates/base.html b/ogcp/templates/base.html
index 5f07fe7..3f55555 100644
--- a/ogcp/templates/base.html
+++ b/ogcp/templates/base.html
@@ -17,6 +17,8 @@
<div class="alert alert-info alert-dismissible fade show m-1" role="alert">
{% elif category == 'error' %}
<div class="alert alert-danger alert-dismissible fade show m-1" role="alert">
+ {% else %}
+ <div class="alert alert-warning alert-dismissible fade show m-1" role="alert">
{% endif %}
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="{{ _('Close') }}">
diff --git a/ogcp/templates/nav.html b/ogcp/templates/nav.html
index 5147a37..d7741ca 100644
--- a/ogcp/templates/nav.html
+++ b/ogcp/templates/nav.html
@@ -9,9 +9,27 @@
<li class="nav-item active">
<a class="nav-link" href="{{ url_for('index') }}">{{ _('Home') }}<span class="sr-only">(current)</span></a>
</li>
+ {% if current_user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('scopes') }}">{{ _('Scopes') }}</a>
</li>
+ {% endif %}
+ </ul>
+
+ <ul class="nav navbar-nav navbar-right">
+ {% if current_user.is_authenticated %}
+
+ <li class="nav-item">
+ <a class="btn btn-danger" href="{{ url_for('logout') }}">{{ _('Logout') }}</a>
+ </li>
+
+ {% else %}
+
+ <li class="nav-item">
+ <a class="btn btn-primary" href="{{ url_for('login') }}">{{ _('Login') }}</a>
+ </li>
+
+ {% endif %}
</ul>
</div>
</nav>
diff --git a/ogcp/views.py b/ogcp/views.py
index 7502067..c7a05e7 100644
--- a/ogcp/views.py
+++ b/ogcp/views.py
@@ -5,6 +5,14 @@ from ogcp.forms.action_forms import (
WOLForm, PartitionForm, ClientDetailsForm, HardwareForm, SessionForm,
ImageRestoreForm, ImageCreateForm, SoftwareForm, BootModeForm
)
+from flask_login import (
+ current_user, LoginManager,
+ login_user, logout_user,
+ login_required
+)
+
+from ogcp.models import User
+from ogcp.forms.auth import LoginForm
from ogcp.og_server import OGServer
from flask_babel import _
from ogcp import app
@@ -33,6 +41,10 @@ PART_SCHEME_CODES = {
2: 'GPT'
}
+login_manager = LoginManager()
+login_manager.init_app(app)
+login_manager.login_view = 'login'
+
def validate_ips(ips, min_len=1, max_len=float('inf')):
valid = True
if len(ips) < min_len:
@@ -74,6 +86,12 @@ def parse_scopes_from_tree(tree, scope_type):
scopes += parse_scopes_from_tree(scope, scope_type)
return scopes
+@login_manager.user_loader
+def load_user(user_id):
+ if user_id == 1:
+ return User()
+ return None
+
@app.before_request
def load_config():
g.server = OGServer()
@@ -90,7 +108,31 @@ def server_error(error):
def index():
return render_template('base.html')
+@app.route('/login', methods=['GET', 'POST'])
+def login():
+ form = LoginForm(request.form)
+ if request.method == 'POST' and form.validate():
+ user = User()
+ form_user = request.form['user']
+ pwd = request.form['pwd']
+ if form_user != app.config['USER']:
+ flash(_('Incorrect user name'))
+ return render_template('auth/login.html', form=form)
+ if pwd != app.config['PASS']:
+ flash(_('Incorrect password'))
+ return render_template('auth/login.html', form=form)
+ login_user(user)
+ return redirect(url_for('scopes'))
+ return render_template('auth/login.html', form=LoginForm())
+
+@app.route("/logout")
+@login_required
+def logout():
+ logout_user()
+ return redirect(url_for('index'))
+
@app.route('/scopes/')
+@login_required
def scopes():
def add_state_and_ips(scope, clients):
if 'ip' in scope:
@@ -115,6 +157,7 @@ def scopes():
return render_template('scopes.html', scopes=scopes, clients=clients)
@app.route('/action/poweroff', methods=['POST'])
+@login_required
def action_poweroff():
ips = parse_ips(request.form.to_dict())
payload = {'clients': list(ips)}
@@ -122,6 +165,7 @@ def action_poweroff():
return redirect(url_for("scopes"))
@app.route('/action/wol', methods=['GET', 'POST'])
+@login_required
def action_wol():
form = WOLForm(request.form)
if request.method == 'POST' and form.validate():
@@ -140,6 +184,7 @@ def action_wol():
return redirect(url_for('scopes'))
@app.route('/action/setup', methods=['GET'])
+@login_required
def action_setup_show():
ips = parse_ips(request.args.to_dict())
db_partitions = get_client_setup(ips)
@@ -161,6 +206,7 @@ def action_setup_show():
return render_template('actions/setup.html', forms=forms)
@app.route('/action/setup/modify', methods=['POST'])
+@login_required
def action_setup_modify():
form = PartitionForm(request.form)
if form.validate():
@@ -208,6 +254,7 @@ def action_setup_modify():
return make_response("400 Bad Request", 400)
@app.route('/action/setup/delete', methods=['POST'])
+@login_required
def action_setup_delete():
form = PartitionForm(request.form)
if form.validate():
@@ -243,6 +290,7 @@ def action_setup_delete():
return make_response("400 Bad Request", 400)
@app.route('/action/image/restore', methods=['GET', 'POST'])
+@login_required
def action_image_restore():
def search_image(images_list, image_id):
for image in images_list:
@@ -315,6 +363,7 @@ def action_image_restore():
return render_template('actions/image_restore.html', form=form)
@app.route('/action/hardware', methods=['GET', 'POST'])
+@login_required
def action_hardware():
form = HardwareForm(request.form)
if request.method == 'POST':
@@ -335,6 +384,7 @@ def action_hardware():
hardware=hardware)
@app.route('/action/software', methods=['GET', 'POST'])
+@login_required
def action_software():
form = SoftwareForm(request.form)
if request.method == 'POST':
@@ -374,6 +424,7 @@ def action_software():
return render_template('actions/software.html', form=form)
@app.route('/action/session', methods=['GET', 'POST'])
+@login_required
def action_session():
form = SessionForm(request.form)
if request.method == 'POST':
@@ -400,6 +451,7 @@ def action_session():
return render_template('actions/session.html', form=form)
@app.route('/action/client/info', methods=['GET'])
+@login_required
def action_client_info():
form = ClientDetailsForm()
ips = parse_ips(request.args.to_dict())
@@ -437,6 +489,7 @@ def action_client_info():
return render_template('actions/client_details.html', form=form)
@app.route('/action/client/add', methods=['GET', 'POST'])
+@login_required
def action_client_add():
form = ClientDetailsForm(request.form)
if request.method == 'POST':
@@ -472,6 +525,7 @@ def action_client_add():
return render_template('actions/client_details.html', form=form)
@app.route('/action/mode', methods=['GET', 'POST'])
+@login_required
def action_mode():
form = BootModeForm(request.form)
if request.method == 'POST':
@@ -500,6 +554,7 @@ def action_mode():
@app.route('/action/image/create', methods=['GET', 'POST'])
+@login_required
def action_image_create():
form = ImageCreateForm(request.form)
if request.method == 'POST':
@@ -545,6 +600,7 @@ def action_image_create():
return render_template('actions/image_create.html', form=form)
@app.route('/action/reboot', methods=['POST'])
+@login_required
def action_reboot():
ips = parse_ips(request.form.to_dict())
if not validate_ips(ips):
@@ -559,6 +615,7 @@ def action_reboot():
return redirect(url_for("scopes"))
@app.route('/action/refresh', methods=['POST'])
+@login_required
def action_refresh():
ips = parse_ips(request.form.to_dict())
if not validate_ips(ips):
diff --git a/requirements.txt b/requirements.txt
index aba7d15..b22ad33 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,6 +7,7 @@ Flask==1.1.2
Flask-Babel==2.0.0
Flask-Bootstrap==3.3.7.1
Flask-WTF==0.14.3
+Flask-Login==0.5.0
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.2