Commit ce6523e3 authored by Pietro Albini's avatar Pietro Albini

Add basic authentication support

parent 2d69f798
......@@ -31,13 +31,14 @@ setuptools.setup(
description = "Source code of the ubuntu-it website",
install_requires = [
"flask",
"click",
"flask",
"flask-openid",
"gunicorn",
"requests",
"itsdangerous",
"toml",
"pyyaml",
"requests",
"toml",
],
packages = [
......
......@@ -18,9 +18,10 @@ import os
import flask
from . import auth
from . import cache
from . import db
from . import pages
from . import cache
from . import utils
from . import download
from . import navbar
......@@ -55,6 +56,7 @@ def create_app(data_path):
app.download.prepare_blueprint(app),
url_prefix="/download",
)
app.register_blueprint(auth.prepare_blueprint(app), url_prefix="/+auth")
app.register_blueprint(pages.prepare_blueprint(app))
......
# Source code of the Ubuntu-it website
# Copyright (C) 2018 Pietro Albini <pietroalbini@ubuntu.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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; witout even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import uuid
import flask
import flask_openid
class SessionError(BaseException):
pass
class Sessions:
def __init__(self, db):
self.db = db
def create(self, nickname, teams):
"""Create a new session and return its ID"""
id = str(uuid.uuid4())
ip = flask.request.remote_addr
self.db.update(
"INSERT INTO auth_sessions (id, nickname, teams, ip) "
"VALUES (?, ?, ?, ?)", id, nickname, ",".join(teams), ip,
)
return id
def check(self, id):
"""Check if a session is valid and return its data"""
data = self.db.query("SELECT nickname, teams, ip FROM auth_sessions WHERE id = ?", id)
if not data:
raise SessionError("La tua sessione è scaduta, accedi di nuovo.")
nickname = data[0][0]
teams = data[0][1].split(",")
ip = data[0][2]
if ip != flask.request.remote_addr:
raise SessionError("Questa sessione è valida solo su un'altra rete, accedi di nuovo.")
return {
"nickname": data[0][0],
"teams": data[0][1].split(","),
}
def delete(self, id):
"""Delete a session"""
self.db.update("DELETE FROM auth_sessions WHERE id = ?;", id)
def prepare_blueprint(app):
"""Prepare the auth blueprint"""
bp = flask.Blueprint("auth", __name__)
oid = flask_openid.OpenID(app, safe_roots=[])
sessions = Sessions(app.db)
@app.before_request
def check_auth():
if "auth" in flask.session:
try:
data = sessions.check(flask.session["auth"])
except SessionError as e:
del flask.session["auth"]
flask.flash(str(e), "error")
return
flask.g.auth_name = data["nickname"]
flask.g.auth_teams = data["teams"]
@oid.after_login
def receive_openid(resp):
flask.session["auth"] = sessions.create(resp.nickname, [])
flask.flash("Benvenuto %s!" % resp.nickname, "success")
return flask.redirect(flask.url_for("pages.index"))
@bp.route("/login")
@oid.loginhandler
def login():
if "auth_name" not in flask.g:
return oid.try_login("https://login.ubuntu.com/+openid", ask_for=["nickname"])
else:
flask.flash("Hai già effettuato l'accesso!", "info")
return flask.redirect(flask.url_for("pages.index"))
@bp.route("/logout")
def logout():
sessions.delete(flask.session["auth"])
del flask.session["auth"]
flask.flash("La sessione è stata terminata correttamente.", "success")
return flask.redirect(flask.url_for("pages.index"))
return bp
......@@ -72,4 +72,13 @@ class Database:
self.query(query, *params, update=True)
MIGRATIONS = []
MIGRATIONS = [
("create_auth_sessions_table", """
CREATE TABLE auth_sessions (
id TEXT PRIMARY KEY,
nickname TEXT NOT NULL,
teams TEXT NOT NULL,
ip TEXT NOT NULL
);
"""),
]
......@@ -44,6 +44,16 @@
</div>
</div>
{% if g.auth_name %}
<nav class="sites-list">
<div class="container">
<ul class="right">
<li><a href="{{ url_for("auth.logout") }}">Esci</a></li>
</ul>
</div>
</nav>
{% endif %}
<nav class="sites-list">
<div class="container">
<ul>
......@@ -121,6 +131,11 @@
<li><a href="https://wiki.ubuntu-it.org/GruppoWeb">
Collabora con noi
</a></li>
{% if not g.auth_name %}
<li><a href="{{ url_for("auth.login") }}">
Accedi
</a></li>
{% endif %}
</ul>
</footer>
</div>
......
Markdown is supported
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