Fixed issues with user authentication.
Improved setup and minor improvements.
This commit is contained in:
parent
6bf54f9fcd
commit
9bb664b097
|
@ -1,11 +1,10 @@
|
|||
Things To-Do
|
||||
============
|
||||
|
||||
* Build out setup.py and make it easy to distribute on PyPI.
|
||||
* Build out user account management and registration. {Started}
|
||||
* Make new logo based on APS' Mr. Penguin. {Started}
|
||||
* Build out simple to-do/project creation and management setup.
|
||||
* Setup a nice clutter-free deployment option for rookeri.es itself. (In-progress)
|
||||
* Setup a nice clutter-free deployment option for rookeri.es itself. {In-progress}
|
||||
|
||||
* Build out documentation with Sphinx.
|
||||
** Make Sphinx output and site look-and-feel match.
|
||||
|
@ -20,3 +19,4 @@ Things Done
|
|||
-----------
|
||||
|
||||
* *2013 May 09* --- Transitioned COPYING to reStructured text.
|
||||
* *2013 June 11* --- Build out setup.py and make it easy to distribute on PyPI.
|
||||
|
|
|
@ -23,16 +23,14 @@ Admin module for Rookeries that adds some special utilities to run outside of th
|
|||
@author: Dorian Pula <dorian.pula@amber-penguin-software.ca>
|
||||
"""
|
||||
|
||||
from rookeries.core.database import db_session, init_db
|
||||
from rookeries.core.database import init_db
|
||||
import sys
|
||||
|
||||
|
||||
def rebuild_database():
|
||||
"""Re-synchronizes the database which is pretty useful for rapid development."""
|
||||
from rookeries.core.models import populate_db_with_user_setup
|
||||
|
||||
init_db()
|
||||
populate_db_with_user_setup(db_session)
|
||||
# TODO Add in some nice switches later...
|
||||
init_db(True, True)
|
||||
|
||||
|
||||
def main(command):
|
||||
|
|
|
@ -28,6 +28,7 @@ Core module that handles database connections in Rookeri.es
|
|||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
from rookeries.core.config import Config
|
||||
|
||||
engine = create_engine(Config().DATABASE_URI, convert_unicode=True)
|
||||
|
@ -37,18 +38,16 @@ Base = declarative_base()
|
|||
Base.query = db_session.query_property()
|
||||
|
||||
|
||||
def init_db():
|
||||
"""Initializes the database and bindings to the models."""
|
||||
# import all modules here that might define models so that
|
||||
# they will be registered properly on the metadata. Otherwise
|
||||
# you will have to import them first before calling init_db()
|
||||
def init_db(drop_tables=False, populate_with_data=False):
|
||||
"""Initializes the database and bindings to the models. Also populates the models with initial data."""
|
||||
|
||||
import rookeries.core.models
|
||||
|
||||
if drop_tables:
|
||||
Base.metadata.drop_all(bind=engine)
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
|
||||
def resync_db():
|
||||
"""Re-synchronizes the database which is pretty useful for rapid development."""
|
||||
from rookeries.core.models import populate_db_with_user_setup
|
||||
|
||||
init_db()
|
||||
populate_db_with_user_setup(db_session)
|
||||
if drop_tables and populate_with_data:
|
||||
# TODO Add in some nice checks for database migration??
|
||||
rookeries.core.models.populate_db_with_init_models(db_session)
|
|
@ -44,6 +44,9 @@ class User(Base):
|
|||
full_name = Column(String(256))
|
||||
email = Column(String(128), unique=True)
|
||||
|
||||
user_auth_id = Column(Integer, ForeignKey("user_authentication.id"))
|
||||
user_authentication = relationship("UserAuthentication", backref="user", cascade="all, delete")
|
||||
|
||||
user_type_id = Column(Integer, ForeignKey('user_type.id'))
|
||||
user_type = relationship("UserType", backref=backref('users', order_by=id))
|
||||
|
||||
|
@ -56,16 +59,12 @@ class User(Base):
|
|||
return "<User('%s', '%s', '%s')>" % (self.username, self.email, self.full_name)
|
||||
|
||||
|
||||
class UserAuthenticaton(Base):
|
||||
"""
|
||||
Separate setup for storing and managing user authentication.
|
||||
"""
|
||||
class UserAuthentication(Base):
|
||||
"""Model for storing and managing user authentication."""
|
||||
|
||||
__tablename__ = "user_authentication"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("user.id"))
|
||||
user = relationship("User", backref=backref("user_authentication", order_by=id))
|
||||
|
||||
password = Column(String(512))
|
||||
security_update_date = Column(DateTime)
|
||||
|
@ -73,9 +72,8 @@ class UserAuthenticaton(Base):
|
|||
status_id = Column(Integer, ForeignKey("status.id"))
|
||||
status = relationship("Status")
|
||||
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
self.status = db_session.query(Status, name="USER_UNKNOWN")
|
||||
def __init__(self):
|
||||
self.status = Status.query.filter(Status.name == "USER_UNKNOWN").first()
|
||||
self.security_update_date = datetime.now()
|
||||
|
||||
|
||||
|
@ -114,9 +112,7 @@ class Status(Base):
|
|||
|
||||
|
||||
# TODO Organize later...
|
||||
def populate_db_with_user_setup(db_session):
|
||||
|
||||
# TODO Make something nicer that queries before adding in a new entry...
|
||||
def populate_db_with_init_models(db_session):
|
||||
|
||||
# Add in types for users.
|
||||
admin_user_type = UserType("admin", True, True)
|
||||
|
|
|
@ -31,50 +31,50 @@ from datetime import datetime
|
|||
from rookeries.core.config import Config
|
||||
|
||||
|
||||
def generate_password_hash(username, user_auth, password, site_secret):
|
||||
def generate_password_hash(user, password, site_secret):
|
||||
"""
|
||||
Generates a proper secure salt with hash attached to a user.
|
||||
"""
|
||||
|
||||
# Inspired by this article on proper handling of salts: http://crackstation.net/hashing-security.htm
|
||||
user_sec_update_date = datetime.isoformat(user_auth.security_update_date)
|
||||
user_sec_update_date = datetime.isoformat(user.user_authentication.security_update_date)
|
||||
|
||||
hashable = username + ";" + password + ";" + site_secret + ";" + user_sec_update_date
|
||||
hashable = user.username + ";" + password + ";" + site_secret + ";" + user_sec_update_date
|
||||
hasher = hashlib.sha512()
|
||||
hasher.update(hashable)
|
||||
|
||||
return unicode(hasher.hexdigest())
|
||||
|
||||
|
||||
def check_password(username, user_auth, password):
|
||||
def check_password(user, password):
|
||||
valid_password = False
|
||||
|
||||
config = Config()
|
||||
if user_auth is not None:
|
||||
attempted_credentials = generate_password_hash(username, user_auth, password, config.SITE_SECRET)
|
||||
actual_credentials = user_auth.password
|
||||
if user is not None:
|
||||
attempted_credentials = generate_password_hash(user, password, config.SITE_SECRET)
|
||||
actual_credentials = user.user_authentication.password
|
||||
valid_password = (actual_credentials == attempted_credentials)
|
||||
|
||||
return valid_password
|
||||
|
||||
|
||||
def change_password(username, user_auth, password):
|
||||
def change_password(user, password):
|
||||
"""
|
||||
Generate the password hash and change it in the object.
|
||||
"""
|
||||
user_auth.security_update_date = datetime.now()
|
||||
hashed_password = generate_password_hash(username, user_auth, password, Config.SITE_SECRET)
|
||||
user_auth.password = hashed_password
|
||||
user.user_authentication.security_update_date = datetime.now()
|
||||
hashed_password = generate_password_hash(user, password, Config.SITE_SECRET)
|
||||
user.user_authentication.password = hashed_password
|
||||
|
||||
|
||||
def check_user_login(user, user_auth, password):
|
||||
def check_user_login(user, password):
|
||||
"""
|
||||
Checks to see if the user can login.
|
||||
"""
|
||||
|
||||
if check_password(user, user_auth, password):
|
||||
if check_password(user, password):
|
||||
# TODO Use a better thing than just magic strings to check status.
|
||||
return user_auth.status.name == "USER_ACTIVE"
|
||||
return user.user_authentication.status.name == "USER_ACTIVE"
|
||||
|
||||
else:
|
||||
return False
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
# TODO Add in comments plus all requistes from requirements.txt
|
||||
# TODO Look into http://stackoverflow.com/questions/4150423/can-pip-install-dependencies-not-specified-in-setup-py-at-install-time
|
||||
|
||||
setup(name='rookeries',
|
||||
version='0.2',
|
||||
description='Python Distribution Utilities',
|
||||
author='Dorian Pula',
|
||||
author_email='dorian.pula@amber-penguin-software.ca',
|
||||
url='http://rookeri.es',
|
||||
packages=['distutils', 'distutils.command'],
|
||||
install_requires= open('app/requirements.txt').readlines(),
|
||||
# install_requires=['setuptools'],
|
||||
)
|
|
@ -30,7 +30,7 @@ import os
|
|||
import datetime
|
||||
from rookeries.core.config import Config
|
||||
from rookeries.core.database import db_session
|
||||
from rookeries.core.models import User, UserAuthenticaton
|
||||
from rookeries.core.models import User, UserAuthentication
|
||||
from rookeries.core.security import check_password, generate_password_hash
|
||||
|
||||
app = Flask(__name__)
|
||||
|
@ -53,10 +53,9 @@ def login():
|
|||
|
||||
# TODO Do try / catch or deal with exceptions?
|
||||
user = User.query.filter(User.username == username).first()
|
||||
user_auth = UserAuthenticaton.query.filter(UserAuthenticaton.user == user).first()
|
||||
|
||||
# TODO Do try / catch or deal with exceptions?
|
||||
valid_password = check_password(user, user_auth, password)
|
||||
valid_password = check_password(user, password)
|
||||
if valid_password is True:
|
||||
# TODO Add in proper authentication tokens instead...
|
||||
session["logged_in"] = True
|
||||
|
@ -163,11 +162,10 @@ def register_user():
|
|||
|
||||
# TODO Add in validation of email... and status that requires email validation of user.
|
||||
user = User(username=username, full_name=user_full_name, email=email)
|
||||
user.user_authentication = UserAuthentication()
|
||||
|
||||
|
||||
user.security_update_date = datetime.datetime.now()
|
||||
hashed_password = generate_password_hash(user, password, Config.SITE_SECRET)
|
||||
user.password = hashed_password
|
||||
user.user_authentication.password = hashed_password
|
||||
# TODO Fix user types... not working very well at the moment... as in not at all.
|
||||
# user.user_type = UserType.id
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
# Copyright (c) 2013 Dorian Pula <dorian.pula@amber-penguin-software.ca>
|
||||
#
|
||||
# Rookeries 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.
|
||||
#
|
||||
# Rookeries is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without 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 Rookeries. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Please share and enjoy!
|
||||
#
|
||||
|
||||
"""
|
||||
Setup for Rookeries web app
|
||||
|
||||
@author: Dorian Pula <dorian.pula@amber-penguin-software.ca>
|
||||
"""
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
# Inspired by
|
||||
# http://stackoverflow.com/questions/4150423/can-pip-install-dependencies-not-specified-in-setup-py-at-install-time
|
||||
|
||||
setup(name='rookeries',
|
||||
version='0.0.2',
|
||||
description='Rookeri.es Task Centric Productivity Suite',
|
||||
author='Dorian Pula',
|
||||
author_email='dorian.pula@amber-penguin-software.ca',
|
||||
url='http://rookeri.es/',
|
||||
packages=['rookeries', 'rookeries.core'],
|
||||
install_requires=open('requirements.txt').readlines(),)
|
Loading…
Reference in New Issue