first pass, non-working

This commit is contained in:
Matthew Scragg 2015-10-13 22:52:30 -05:00
vecāks 459a9c2c59
revīzija 3c2f4a0445
17 mainīti faili ar 295 papildinājumiem un 121 dzēšanām

Parādīt failu

@ -161,4 +161,4 @@ if ENV != "DEV":
ASSETS_DEBUG = False
SQLALCHEMY_ECHO = False
MODULES = ['wiki', 'auth', 'search']
MODULES = ['wiki', 'search', 'auth', 'auth.local', 'auth.oauth']

Parādīt failu

@ -1,9 +1,10 @@
import click
from realms.lib.util import random_string
from realms.modules.auth.models import User
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

Parādīt failu

@ -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)

Parādīt failu

@ -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)

Parādīt failu

@ -1,39 +1,41 @@
from flask import current_app
from flask.ext.login import UserMixin, logout_user, login_user, AnonymousUserMixin
from realms import login_manager, db
from realms.lib.model import Model
from realms import login_manager
from realms.lib.util import gravatar_url
from itsdangerous import URLSafeSerializer, BadSignature
from hashlib import sha256
import bcrypt
import importlib
@login_manager.user_loader
def load_user(user_id):
return User.get_by_id(user_id)
def load_user(auth_id):
return Auth.load_user(auth_id)
auth_users = {}
@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)
class Auth(object):
if not payload:
return None
@staticmethod
def get_auth_user(auth_type):
print auth_type
mod = importlib.import_module('realms.modules.auth.%s.models' % auth_type)
return mod.User
# User key *could* be stored in payload to avoid user lookup in db
user = User.get_by_id(payload.get('id'))
@staticmethod
def load_user(auth_id):
print auth_id
auth_type, user_id = auth_id.split("/")
return Auth.get_auth_user(auth_type).load_user(user_id)
if not user:
return None
try:
if User.signer(sha256(user.password).hexdigest()).loads(token):
return user
else:
return None
except BadSignature:
return None
@staticmethod
def login_forms():
forms = []
# TODO be dynamic
for t in ['local']:
forms.append(Auth.get_auth_user(t).login_form())
return forms
class AnonUser(AnonymousUserMixin):
@ -42,40 +44,42 @@ class AnonUser(AnonymousUserMixin):
admin = False
class User(Model, UserMixin):
__tablename__ = 'users'
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
class BaseUser(UserMixin):
id = None
email = None
username = None
type = 'base'
hidden_fields = ['password']
readonly_fields = ['email', 'password']
def get_id(self):
return unicode("%s/%s" % (self.type, self.id))
def get_auth_token(self):
key = sha256(self.password).hexdigest()
return User.signer(key).dumps(dict(id=self.id))
key = sha256(self.auth_token_id).hexdigest()
return BaseUser.signer(key).dumps(dict(id=self.id))
@property
def auth_token_id(self):
raise NotImplementedError
@property
def avatar(self):
return gravatar_url(self.email)
@staticmethod
def create(username, email, password):
u = User()
u.username = username
u.email = email
u.password = User.hash_password(password)
u.save()
def load_user(*args, **kwargs):
raise NotImplementedError
@staticmethod
def create(*args, **kwargs):
pass
@staticmethod
def get_by_username(username):
return User.query().filter_by(username=username).first()
pass
@staticmethod
def get_by_email(email):
return User.query().filter_by(email=email).first()
pass
@staticmethod
def signer(salt):
@ -83,19 +87,7 @@ class User(Model, UserMixin):
@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
raise NotImplementedError()
@staticmethod
def hash_password(password):
@ -109,4 +101,8 @@ class User(Model, UserMixin):
def logout(cls):
logout_user()
@staticmethod
def login_form():
pass
login_manager.anonymous_user = AnonUser

Parādīt failu

@ -0,0 +1,36 @@
from flask import render_template
from flask_oauthlib.client import OAuth
from realms import config
from ..models import BaseUser
oauth = OAuth()
class OAuthUser(BaseUser):
# OAuth remote app
app = None
class TwitterUser(OAuthUser):
app = oauth.remote_app(
'twitter',
base_url='https://api.twitter.com/1/',
request_token_url='https://api.twitter.com/oauth/request_token',
access_token_url='https://api.twitter.com/oauth/access_token',
authorize_url='https://api.twitter.com/oauth/authenticate',
consumer_key=config.TWITTER_KEY,
consumer_secret=config.TWITTER_SECRET)
def __init__(self, id_, username, email=None):
self.id = id_
self.username = username
self.email = email
@staticmethod
def load_user(*args, **kwargs):
return TwitterUser(args[0])
@staticmethod
def login_form():
return render_template('auth/oauth/twitter.html')

Parādīt failu

@ -0,0 +1,30 @@
from flask import Blueprint, url_for, request, flash, redirect
from .models import TwitterUser
blueprint = Blueprint('auth.oauth', __name__)
def oauth_failed(next_url):
flash(u'You denied the request to sign in.')
return redirect(next_url)
@blueprint.route("/login/twitter")
def login_twitter():
return TwitterUser.app.authorize(callback=url_for('twitter_callback',
next=request.args.get('next') or request.referrer or None))
@blueprint.route('/login/twitter/callback')
def twitter_callback():
next_url = request.args.get('next') or url_for('index')
resp = TwitterUser.app.authorized_response()
if resp is None:
return oauth_failed(next_url)
session['twitter_token'] = (
resp['oauth_token'],
resp['oauth_token_secret']
)
session['twitter_user'] = resp['screen_name']
flash('You were signed in as %s' % resp['screen_name'])
return redirect(next_url)

Parādīt failu

@ -1,72 +1,22 @@
from flask import current_app, render_template, request, redirect, Blueprint, flash, url_for
from realms.modules.auth.models import User
from realms.modules.auth.forms import LoginForm, RegistrationForm
from flask.ext.login import logout_user
from realms.modules.auth.models import Auth
blueprint = Blueprint('auth', __name__)
@blueprint.route("/logout")
def logout_page():
User.logout()
flash("You are now logged out")
return redirect(url_for(current_app.config['ROOT_ENDPOINT']))
@blueprint.route("/login", methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == "POST":
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'))
return render_template("auth/login.html", form=form)
return render_template("auth/login.html", forms=Auth.login_forms())
@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.register'))
if User.get_by_username(request.form['username']):
flash('Username is taken', 'warning')
return redirect(url_for('auth.register'))
if User.get_by_email(request.form['email']):
flash('Email is taken', 'warning')
return redirect(url_for('auth.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)
@blueprint.route("/logout")
def logout():
logout_user()
flash("You are now logged out")
return redirect(url_for(current_app.config['ROOT_ENDPOINT']))
@blueprint.route("/settings", methods=['GET', 'POST'])
def settings():
return render_template("auth/settings.html")
@blueprint.route("/logout")
def logout():
User.logout()
return redirect(url_for(current_app.config['ROOT_ENDPOINT']))

Parādīt failu

@ -0,0 +1,5 @@
{% from 'macros.html' import render_form, render_field %}
{% call render_form(form, action_url=url_for('auth.local.login'), action_text='Login', btn_class='btn btn-primary') %}
{{ render_field(form.email, placeholder='Email', type='email', required=1) }}
{{ render_field(form.password, placeholder='Password', type='password', required=1) }}
{% endcall %}

Parādīt failu

@ -1,8 +1,6 @@
{% extends 'layout.html' %}
{% from 'macros.html' import render_form, render_field %}
{% block body %}
{% call render_form(form, action_url=url_for('auth.login'), action_text='Login', btn_class='btn btn-primary') %}
{{ render_field(form.email, placeholder='Email', type='email', required=1) }}
{{ render_field(form.password, placeholder='Password', type='password', required=1) }}
{% endcall %}
{% for form in forms %}
{{ form|safe }}
{% endfor %}
{% endblock %}

Parādīt failu

@ -1,7 +1,7 @@
{% extends 'layout.html' %}
{% from 'macros.html' import render_form, render_field %}
{% block body %}
{% call render_form(form, action_url=url_for('auth.register'), action_text='Register', btn_class='btn btn-primary') %}
{% call render_form(form, action_url=url_for('auth.local.register'), action_text='Register', btn_class='btn btn-primary') %}
{{ render_field(form.username, placeholder='Username', type='username', **{"required": 1, "data-parsley-type": "alphanum"}) }}
{{ render_field(form.email, placeholder='Email', type='email', required=1) }}
{{ render_field(form.password, placeholder='Password', type='password', **{"required": 1, "data-parsley-minlength": "6"}) }}

Parādīt failu

@ -74,7 +74,7 @@
{% else %}
<li><a href="{{ url_for('auth.login') }}"><i class="fa fa-user"></i> &nbsp;Login</a></li>
{% if config.REGISTRATION_ENABLED %}
<li><a href="{{ url_for('auth.register') }}"><i class="fa fa-users"></i> &nbsp;Register</a></li>
<li><a href="{{ url_for('auth.local.register') }}"><i class="fa fa-users"></i> &nbsp;Register</a></li>
{% endif %}
{% endif %}
</ul>