first pass, non-working

This commit is contained in:
Matthew Scragg 2015-10-13 22:52:30 -05:00
parent 459a9c2c59
commit 3c2f4a0445
17 changed files with 295 additions and 121 deletions

View file

View file

@ -0,0 +1,37 @@
import click
from realms.lib.util import random_string
from realms.modules.auth.local.models import User
from realms.lib.util import green, red, yellow
from realms import flask_cli
@flask_cli.group(short_help="Auth Module")
def cli():
pass
@cli.command()
@click.argument('username')
@click.argument('email')
@click.option('--password', help='Leave blank for random password')
def create_user(username, email, password):
""" Create a new user
"""
show_pass = not password
if not password:
password = random_string(12)
if User.get_by_username(username):
red("Username %s already exists" % username)
return
if User.get_by_email(email):
red("Email %s already exists" % email)
return
User.create(username, email, password)
green("User %s created" % username)
if show_pass:
yellow("Password: %s" % password)

View file

@ -0,0 +1,17 @@
from flask_wtf import Form
from wtforms import StringField, PasswordField, validators
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('Password', [
validators.DataRequired(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
class LoginForm(Form):
email = StringField('Email', [validators.DataRequired()])
password = PasswordField('Password', [validators.DataRequired()])

View file

@ -0,0 +1,8 @@
from flask import current_app
from flask_wtf import RecaptchaField
from .forms import RegistrationForm
def before_first_request():
if current_app.config['RECAPTCHA_ENABLE']:
setattr(RegistrationForm, 'recaptcha', RecaptchaField("You Human?"))

View file

@ -0,0 +1,107 @@
from flask import current_app, render_template
from flask.ext.login import logout_user, login_user
from realms import login_manager, db
from realms.lib.model import Model
from ..models import BaseUser
from .forms import LoginForm
from itsdangerous import URLSafeSerializer, BadSignature
from hashlib import sha256
import bcrypt
@login_manager.token_loader
def load_token(token):
# Load unsafe because payload is needed for sig
sig_okay, payload = URLSafeSerializer(current_app.config['SECRET_KEY']).loads_unsafe(token)
if not payload:
return None
# User key *could* be stored in payload to avoid user lookup in db
user = User.get_by_id(payload.get('id'))
if not user:
return None
try:
if BaseUser.signer(sha256(user.password).hexdigest()).loads(token):
return user
else:
return None
except BadSignature:
return None
class User(Model, BaseUser):
__tablename__ = 'users'
type = 'local'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(128), unique=True)
email = db.Column(db.String(128), unique=True)
password = db.Column(db.String(60))
admin = False
hidden_fields = ['password']
readonly_fields = ['email', 'password']
@property
def auth_token_id(self):
return self.password
@staticmethod
def load_user(*args, **kwargs):
return User.get_by_id(args[0])
@staticmethod
def create(username, email, password):
u = User()
u.username = username
u.email = email
u.password = User.hash_password(password)
u.save()
@staticmethod
def get_by_username(username):
return User.query().filter_by(username=username).first()
@staticmethod
def get_by_email(email):
return User.query().filter_by(email=email).first()
@staticmethod
def signer(salt):
return URLSafeSerializer(current_app.config['SECRET_KEY'] + salt)
@staticmethod
def auth(email, password):
user = User.get_by_email(email)
if not user:
# User doesn't exist
return False
if User.check_password(password, user.password):
# Password is good, log in user
login_user(user, remember=True)
return user
else:
# Password check failed
return False
@staticmethod
def hash_password(password):
return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12))
@staticmethod
def check_password(password, hashed):
return bcrypt.hashpw(password.encode('utf-8'), hashed.encode('utf-8')) == hashed
@classmethod
def logout(cls):
logout_user()
@staticmethod
def login_form():
form = LoginForm()
return render_template('auth/local/login.html', form=form)

View file

@ -0,0 +1,51 @@
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for
from realms.modules.auth.local.models import User
from realms.modules.auth.local.forms import LoginForm, RegistrationForm
blueprint = Blueprint('auth.local', __name__)
@blueprint.route("/login/local", methods=['POST'])
def login():
form = LoginForm()
if not form.validate():
flash('Form invalid', 'warning')
return redirect(url_for('auth.login'))
if User.auth(request.form['email'], request.form['password']):
return redirect(request.args.get("next") or url_for(current_app.config['ROOT_ENDPOINT']))
else:
flash('Email or Password Incorrect', 'warning')
return redirect(url_for('auth.login'))
@blueprint.route("/register", methods=['GET', 'POST'])
def register():
if not current_app.config['REGISTRATION_ENABLED']:
flash("Registration is disabled")
return redirect(url_for(current_app.config['ROOT_ENDPOINT']))
form = RegistrationForm()
if request.method == "POST":
if not form.validate():
flash('Form invalid', 'warning')
return redirect(url_for('auth.local.register'))
if User.get_by_username(request.form['username']):
flash('Username is taken', 'warning')
return redirect(url_for('auth.local.register'))
if User.get_by_email(request.form['email']):
flash('Email is taken', 'warning')
return redirect(url_for('auth.local.register'))
User.create(request.form['username'], request.form['email'], request.form['password'])
User.auth(request.form['email'], request.form['password'])
return redirect(request.args.get("next") or url_for(current_app.config['ROOT_ENDPOINT']))
return render_template("auth/register.html", form=form)