mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-05-02 03:02:23 +02:00
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
This commit is contained in:
parent
db29648956
commit
a836085448
6 changed files with 54 additions and 25 deletions
|
@ -3,10 +3,12 @@ Changelog
|
||||||
|
|
||||||
This document describes changes between each past release.
|
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)
|
1.0 (2017-06-20)
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
from flask_script import Manager
|
from flask_script import Manager, Command
|
||||||
from flask_migrate import Migrate, MigrateCommand
|
from flask_migrate import Migrate, MigrateCommand
|
||||||
|
from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
from run import app
|
from run import app
|
||||||
from models import db
|
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)
|
migrate = Migrate(app, db)
|
||||||
|
|
||||||
manager = Manager(app)
|
manager = Manager(app)
|
||||||
manager.add_command('db', MigrateCommand)
|
manager.add_command('db', MigrateCommand)
|
||||||
|
manager.add_command('generate_password_hash', GeneratePasswordHash)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -52,6 +52,17 @@ def configure():
|
||||||
if not 'MAIL_DEFAULT_SENDER' in app.config:
|
if not 'MAIL_DEFAULT_SENDER' in app.config:
|
||||||
app.config['MAIL_DEFAULT_SENDER'] = DEFAULT_MAIL_SENDER
|
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()
|
configure()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import json
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from werkzeug.security import generate_password_hash
|
||||||
from flask import session
|
from flask import session
|
||||||
|
|
||||||
# Unset configuration file env var if previously set
|
# Unset configuration file env var if previously set
|
||||||
|
@ -376,7 +377,7 @@ class BudgetTestCase(TestCase):
|
||||||
self.assertNotIn('raclette', session)
|
self.assertNotIn('raclette', session)
|
||||||
|
|
||||||
def test_admin_authentication(self):
|
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
|
# test the redirection to the authentication page when trying to access admin endpoints
|
||||||
resp = self.app.get("/create")
|
resp = self.app.get("/create")
|
||||||
|
|
|
@ -13,6 +13,8 @@ from flask import Blueprint, current_app, flash, g, redirect, \
|
||||||
render_template, request, session, url_for, send_file
|
render_template, request, session, url_for, send_file
|
||||||
from flask_mail import Mail, Message
|
from flask_mail import Mail, Message
|
||||||
from flask_babel import get_locale, gettext as _
|
from flask_babel import get_locale, gettext as _
|
||||||
|
from werkzeug.security import generate_password_hash, \
|
||||||
|
check_password_hash
|
||||||
from smtplib import SMTPRecipientsRefused
|
from smtplib import SMTPRecipientsRefused
|
||||||
import werkzeug
|
import werkzeug
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
|
@ -35,10 +37,10 @@ def requires_admin(f):
|
||||||
"""
|
"""
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def admin_auth(*args, **kws):
|
def admin_auth(*args, **kws):
|
||||||
admin_password = session.get('admin_password', '')
|
is_admin = session.get('is_admin')
|
||||||
if not admin_password == current_app.config['ADMIN_PASSWORD']:
|
if is_admin or not current_app.config['ADMIN_PASSWORD']:
|
||||||
raise Redirect303(url_for('.admin', goto=request.path))
|
return f(*args, **kws)
|
||||||
return f(*args, **kws)
|
raise Redirect303(url_for('.admin', goto=request.path))
|
||||||
return admin_auth
|
return admin_auth
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,8 +89,8 @@ def admin():
|
||||||
goto = request.args.get('goto', url_for('.home'))
|
goto = request.args.get('goto', url_for('.home'))
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if form.validate():
|
if form.validate():
|
||||||
if form.admin_password.data == current_app.config['ADMIN_PASSWORD']:
|
if check_password_hash(current_app.config['ADMIN_PASSWORD'], form.admin_password.data):
|
||||||
session['admin_password'] = form.admin_password.data
|
session['is_admin'] = True
|
||||||
session.update()
|
session.update()
|
||||||
return redirect(goto)
|
return redirect(goto)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -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
|
first time, you will need to take a few moments to configure the application
|
||||||
properly.
|
properly.
|
||||||
|
|
||||||
+----------------------------+---------------------------+-----------------------------------------------------------------------------+
|
+----------------------------+---------------------------+----------------------------------------------------------------------------------------+
|
||||||
| Setting name | Default | What does it do? |
|
| 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 |
|
| 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`. |
|
| | | 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**. |
|
| 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 |
|
| MAIL_DEFAULT_SENDER | ``("Budget manager", | A python tuple describing the name and email adress to use when sending |
|
||||||
| | "budget@notmyidea.org")`` | emails. |
|
| | "budget@notmyidea.org")`` | emails. |
|
||||||
+----------------------------+---------------------------+-----------------------------------------------------------------------------+
|
+----------------------------+---------------------------+----------------------------------------------------------------------------------------+
|
||||||
| ACTIVATE_DEMO_PROJECT | ``True`` | If set to `True`, a demo project will be available on the frontpage. |
|
| 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 |
|
| | ``""`` | 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
|
.. _`the SQLAlechemy documentation`: http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue