Commit 33ce6378 authored by ale's avatar ale
Browse files

support optional authentication to protect the certificate generation

parent b46b7066
......@@ -71,3 +71,15 @@ VPN_CA_SUBJECT
In this latter case, the autoca web application will be available
under the /ca/ URL prefix.
The VPN web application supports authentication (to control who has
access to the certificate generation). To enable it, define the
following variables:
Set this to True to enable authentication
Set this to a function that should accept two arguments (username
and password) and return a True/Fals result.
......@@ -57,3 +57,12 @@ a:hover {
.footer a {
text-decoration: none;
input {
font-size: 1.2em;
.center {
text-align: center;
......@@ -15,7 +15,7 @@
<div style="display:none;">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<p style="text-align:center;">
<p class="center">
<input type="submit" value=" Generate new SSL certificate ">
{% extends "_base.html" %}
{% block content %}
Enter your authentication credentials:
{% if error %}
<p class="center" style="color:red;">{{ error }}</p>
{% endif %}
<form action="{{ url_for('vpn_admin.login') }}" method="post">
<div style="display:none;">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<p class="center">
<input type="text" size="20" placeholder="Email"
name="username" value="{{ username }}"><br>
<input type="password" size="20" placeholder="Password"
<input type="submit" value="Login">
<b>NOTE:</b> the credentials are only used to limit access
to this application. They will not be saved, nor they will
ever be associated with the VPN connection.
{% endblock %}
......@@ -10,7 +10,7 @@ from autoca import ca
from autoca import ca_app
from autoca import ca_stub
from flask import Blueprint, Flask, abort, redirect, request, make_response, \
render_template, session, g, current_app
render_template, session, g, current_app, url_for
vpn_admin = Blueprint('vpn_admin', __name__)
log = logging.getLogger(__name__)
......@@ -118,15 +118,28 @@ Further info:
def csrf(fn):
def csrf(methods=('POST',)):
def _csrf(fn):
def _csrf_wrapper(*args, **kwargs):
if request.method in methods:
query_args = (request.method == 'POST') and request.form or request.args
token = session.pop('_csrf', None)
if not token or token != query_args.get('_csrf'):
return fn(*args, **kwargs)
return _csrf_wrapper
return _csrf
def auth(fn):
def _csrf_wrapper(*args, **kwargs):
query_args = (request.method == 'POST') and request.form or request.args
token = session.pop('_csrf', None)
if not token or token != query_args.get('_csrf'):
def _auth_wrapper(*args, **kwargs):
if current_app.config.get('AUTH_ENABLE'):
if not session.get('logged_in'):
return redirect(url_for('vpn_admin.login'))
return fn(*args, **kwargs)
return _csrf_wrapper
return _auth_wrapper
def generate_csrf_token():
......@@ -140,29 +153,47 @@ def set_ca_wrapper(): =
def check_userlogin():
g.username = None
if 'username' in session:
g.username = session['username']
def index():
return render_template('index.html')
@vpn_admin.route('/newcert', methods=['POST'])
@vpn_admin.route('/login', methods=['GET', 'POST'])
def login():
error = None
username = ''
if request.method == 'POST':
username = request.form.get('username', '')
password = request.form.get('password', '')
if current_app.config['AUTH_FUNCTION'](username, password):
session['logged_in'] = True
return redirect(url_for('vpn_admin.new_cert',
error = 'Authentication failed'
return render_template('login.html', error=error, username=username)
def logout():
session.pop('logged_in', None)
return redirect(url_for('vpn_admin.index'))
@vpn_admin.route('/newcert', methods=['GET', 'POST'])
@csrf(methods=['GET', 'POST'])
def new_cert():
session['dl_ok'] = 'y'
session['dl_ok'] = True
return render_template('download.html')
def new_cert_dl():
if session.pop('dl_ok', None) != 'y':
if not session.pop('dl_ok', None):
return render_template('download_retry.html')
# Create and sign a certificate.
......@@ -257,6 +288,8 @@ if __name__ == '__main__':
built by <a href=""></a>
'AUTH_FUNCTION': lambda x, y: (x and y and x == y),
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment