aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author0livd <0livd@users.noreply.github.com>2017-06-27 00:16:32 +0200
committerAlexis Metaireau <alexis@notmyidea.org>2017-06-27 00:16:32 +0200
commita8360854489d060367cc17ef7933c867228a88e1 (patch)
treea2b8973f131e2db12497fd937c63664dce73ed09
parentdb296489568259a38bc614a1fcc4b504a2ffc983 (diff)
downloadihatemoney-mirror-a8360854489d060367cc17ef7933c867228a88e1.zip
ihatemoney-mirror-a8360854489d060367cc17ef7933c867228a88e1.tar.gz
ihatemoney-mirror-a8360854489d060367cc17ef7933c867228a88e1.tar.bz2
Use a hashed password for ADMIN_PASSWORD (#236)
* Use a hashed password for ADMIN_PASSWORD A generate_password_hash manage.py command is provided Fixes #233 * Print a console warning for users using a clear text ADMIN_PASSWORD * Reword ADMIN_PASSWORD doc * Update changelog * Update CHANGELOG.rst - say it out loud - bump to 2.0 (that's the logic of semantic versioning while introducing breaking changes) * Bump to 2.0 (breaking change) * Update hashed password warning message * Mention the generate password hash in the Changelog
-rw-r--r--CHANGELOG.rst6
-rwxr-xr-xbudget/manage.py13
-rw-r--r--budget/run.py11
-rw-r--r--budget/tests/tests.py3
-rw-r--r--budget/web.py14
-rw-r--r--docs/installation.rst32
6 files changed, 54 insertions, 25 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index fa0724d..7e5514c 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -3,10 +3,12 @@ Changelog
This document describes changes between each past release.
-1.1 (unreleased)
+2.0 (unreleased)
----------------
-- Nothing changed yet.
+### Changed
+
+- **BREAKING CHANGE** Use a hashed ``ADMIN_PASSWORD`` instead of a clear text one, ``./budget/manage.py generate_password_hash`` can be used to generate a proper password HASH (#236)
1.0 (2017-06-20)
diff --git a/budget/manage.py b/budget/manage.py
index 94a21a2..f717fed 100755
--- a/budget/manage.py
+++ b/budget/manage.py
@@ -1,15 +1,26 @@
#!/usr/bin/env python
-from flask_script import Manager
+from flask_script import Manager, Command
from flask_migrate import Migrate, MigrateCommand
+from werkzeug.security import generate_password_hash
from run import app
from models import db
+from getpass import getpass
+
+
+class GeneratePasswordHash(Command):
+ "Get password from user and hash it without printing it in clear text"
+
+ def run(self):
+ password = getpass(prompt='Password: ')
+ print(generate_password_hash(password))
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
+manager.add_command('generate_password_hash', GeneratePasswordHash)
if __name__ == '__main__':
diff --git a/budget/run.py b/budget/run.py
index 00d4326..b576f72 100644
--- a/budget/run.py
+++ b/budget/run.py
@@ -52,6 +52,17 @@ def configure():
if not 'MAIL_DEFAULT_SENDER' in app.config:
app.config['MAIL_DEFAULT_SENDER'] = DEFAULT_MAIL_SENDER
+ if "pbkdf2:sha256:" not in app.config['ADMIN_PASSWORD'] and app.config['ADMIN_PASSWORD']:
+ # Since 2.0
+ warnings.warn(
+ "The way Ihatemoney stores your ADMIN_PASSWORD has changed. You are using an unhashed"
+ +" ADMIN_PASSWORD, which is not supported anymore and won't let you access your admin"
+ +" endpoints. Please use the command './budget/manage.py generate_password_hash'"
+ +" to generate a proper password HASH and copy the output to the value of"
+ +" ADMIN_PASSWORD in your settings file.",
+ UserWarning
+ )
+
configure()
diff --git a/budget/tests/tests.py b/budget/tests/tests.py
index a1cedfa..16aaae9 100644
--- a/budget/tests/tests.py
+++ b/budget/tests/tests.py
@@ -10,6 +10,7 @@ import json
from collections import defaultdict
import six
+from werkzeug.security import generate_password_hash
from flask import session
# Unset configuration file env var if previously set
@@ -376,7 +377,7 @@ class BudgetTestCase(TestCase):
self.assertNotIn('raclette', session)
def test_admin_authentication(self):
- run.app.config['ADMIN_PASSWORD'] = "pass"
+ run.app.config['ADMIN_PASSWORD'] = generate_password_hash("pass")
# test the redirection to the authentication page when trying to access admin endpoints
resp = self.app.get("/create")
diff --git a/budget/web.py b/budget/web.py
index 3bfa73a..ff157b6 100644
--- a/budget/web.py
+++ b/budget/web.py
@@ -13,6 +13,8 @@ from flask import Blueprint, current_app, flash, g, redirect, \
render_template, request, session, url_for, send_file
from flask_mail import Mail, Message
from flask_babel import get_locale, gettext as _
+from werkzeug.security import generate_password_hash, \
+ check_password_hash
from smtplib import SMTPRecipientsRefused
import werkzeug
from sqlalchemy import orm
@@ -35,10 +37,10 @@ def requires_admin(f):
"""
@wraps(f)
def admin_auth(*args, **kws):
- admin_password = session.get('admin_password', '')
- if not admin_password == current_app.config['ADMIN_PASSWORD']:
- raise Redirect303(url_for('.admin', goto=request.path))
- return f(*args, **kws)
+ is_admin = session.get('is_admin')
+ if is_admin or not current_app.config['ADMIN_PASSWORD']:
+ return f(*args, **kws)
+ raise Redirect303(url_for('.admin', goto=request.path))
return admin_auth
@@ -87,8 +89,8 @@ def admin():
goto = request.args.get('goto', url_for('.home'))
if request.method == "POST":
if form.validate():
- if form.admin_password.data == current_app.config['ADMIN_PASSWORD']:
- session['admin_password'] = form.admin_password.data
+ if check_password_hash(current_app.config['ADMIN_PASSWORD'], form.admin_password.data):
+ session['is_admin'] = True
session.update()
return redirect(goto)
else:
diff --git a/docs/installation.rst b/docs/installation.rst
index 785ccc6..3cd143d 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -72,21 +72,23 @@ ihatemoney relies on a configuration file. If you run the application for the
first time, you will need to take a few moments to configure the application
properly.
-+----------------------------+---------------------------+-----------------------------------------------------------------------------+
-| Setting name | Default | What does it do? |
-+============================+===========================+=============================================================================+
-| SQLALCHEMY_DATABASE_URI | ``sqlite:///budget.db`` | Specifies the type of backend to use and its location. More information |
-| | | on the format used can be found on `the SQLAlchemy documentation`. |
-+----------------------------+---------------------------+-----------------------------------------------------------------------------+
-| SECRET_KEY | ``tralala`` | The secret key used to encrypt the cookies. **This needs to be changed**. |
-+----------------------------+---------------------------+-----------------------------------------------------------------------------+
-| MAIL_DEFAULT_SENDER | ``("Budget manager", | A python tuple describing the name and email adress to use when sending |
-| | "budget@notmyidea.org")`` | emails. |
-+----------------------------+---------------------------+-----------------------------------------------------------------------------+
-| ACTIVATE_DEMO_PROJECT | ``True`` | If set to `True`, a demo project will be available on the frontpage. |
-+----------------------------+---------------------------+-----------------------------------------------------------------------------+
-| ADMIN_PASSWORD | ``""`` | If not empty, the specified password must be entered to create new projects |
-+----------------------------+---------------------------+-----------------------------------------------------------------------------+
++----------------------------+---------------------------+----------------------------------------------------------------------------------------+
+| Setting name | Default | What does it do? |
++============================+===========================+========================================================================================+
+| SQLALCHEMY_DATABASE_URI | ``sqlite:///budget.db`` | Specifies the type of backend to use and its location. More information |
+| | | on the format used can be found on `the SQLAlchemy documentation`. |
++----------------------------+---------------------------+----------------------------------------------------------------------------------------+
+| SECRET_KEY | ``tralala`` | The secret key used to encrypt the cookies. **This needs to be changed**. |
++----------------------------+---------------------------+----------------------------------------------------------------------------------------+
+| MAIL_DEFAULT_SENDER | ``("Budget manager", | A python tuple describing the name and email adress to use when sending |
+| | "budget@notmyidea.org")`` | emails. |
++----------------------------+---------------------------+----------------------------------------------------------------------------------------+
+| ACTIVATE_DEMO_PROJECT | ``True`` | If set to `True`, a demo project will be available on the frontpage. |
++----------------------------+---------------------------+----------------------------------------------------------------------------------------+
+| | ``""`` | If not empty, the specified password must be entered to create new projects. |
+| ADMIN_PASSWORD | | To generate the proper password HASH, use ``./budget/manage.py generate_password_hash``|
+| | | and copy its output into the value of *ADMIN_PASSWORD*. |
++----------------------------+---------------------------+----------------------------------------------------------------------------------------+
.. _`the SQLAlechemy documentation`: http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls