mirror of https://git.48k.eu/ogcp
Add login
Ogcp requires a simple login page in order to avoid exposure of the ogServer API to anyone trying to access the web page. Because the main authorization mechanism in ogServer is the api token the login implemented for the ogcp does not include registration process but a single user and password specified in the ogcp.json. "USER": "user", "PASS": "pass" Adds two new views: /login and /logout. They are used to login the user so that the rest of views regarding ogServer functionality can be accessed in a "login required" fashion. Index view (/) is an exception, it can be accessed logged in or not so different data can be displayed. Templates can now access a variable "current_user" to get information about login status. This is a Flask-Login feature. - Templates regarding login can be found in templates/auth/ - Login form is defined in forms/auth.py to separate it from action_forms.py - Adds Flask-Login module to requirements.txt - Adds default user and pass in ogcp.jsonmulti-ogserver
parent
149dfdcbfd
commit
9ee0565ac4
|
@ -2,4 +2,6 @@
|
|||
"IP": "127.0.0.1",
|
||||
"PORT": 8888,
|
||||
"API_TOKEN": "c3fe7bb0395747ec42a25df027585871"
|
||||
"USER": "user",
|
||||
"PASS": "pass"
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
from flask_login import UserMixin
|
||||
|
||||
class User(UserMixin):
|
||||
def get_id(self):
|
||||
return 1
|
|
@ -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 %}
|
|
@ -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') }}">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue