Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os
- import base64
- from io import BytesIO
- from flask import Flask, render_template, request, redirect, url_for, flash, session,
- abort
- from werkzeug.security import generate_password_hash, check_password_hash
- from flask_sqlalchemy import SQLAlchemy
- from flask_login import LoginManager, UserMixin, login_user, logout_user,
- current_user
- from flask_bootstrap import Bootstrap
- from flask_wtf import FlaskForm
- from wtforms import StringField, PasswordField, SubmitField, SelectField
- from wtforms.validators import Required, Length, EqualTo
- import onetimepass
- import pyqrcode
- from datetime import datetime, date, time, timedelta
- from sqlalchemy import Table, Column, Integer, ForeignKey
- from sqlalchemy.orm import relationship
- from sqlalchemy.ext.declarative import declarative_base
- from flask_security import Security, SQLAlchemyUserDatastore,
- UserMixin, RoleMixin, login_required
- # create application instance
- app = Flask(__name__)
- app.config.from_object('config')
- # initialize extensions
- bootstrap = Bootstrap(app)
- db = SQLAlchemy(app)
- lm = LoginManager(app)
- Base = declarative_base()
- # Define models
- roles_users = db.Table('roles_users',
- db.Column('users_id', db.Integer(), db.ForeignKey('users.id')),
- db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
- class Role(db.Model, RoleMixin):
- id = db.Column(db.Integer(), primary_key=True)
- name = db.Column(db.String(80), unique=True)
- description = db.Column(db.String(255))
- class User(UserMixin, db.Model):
- """User model."""
- __tablename__ = 'users'
- id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True)
- username = db.Column(db.String(64), unique=True, index=True)
- password_hash = db.Column(db.String(128))
- otp_secret = db.Column(db.String(16))
- access = db.Column(db.String(16))
- roles = db.relationship('Role', secondary=roles_users,
- backref=db.backref('users', lazy='dynamic'))
- def __init__(self, **kwargs):
- super(User, self).__init__(**kwargs)
- if self.otp_secret is None:
- # generate a random secret
- self.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8')
- @property
- def password(self):
- raise AttributeError('password is not a readable attribute')
- @password.setter
- def password(self, password):
- self.password_hash = generate_password_hash(password)
- def verify_password(self, password):
- return check_password_hash(self.password_hash, password)
- def get_totp_uri(self):
- return 'otpauth://totp/2FA-Demo:{0}?secret={1}&issuer=2FA-Demo'
- .format(self.username, self.otp_secret)
- def verify_totp(self, token):
- return onetimepass.valid_totp(token, self.otp_secret)
- ################################################################################
- user_datastore = SQLAlchemyUserDatastore(db, User, Role)
- security = Security(app, user_datastore)
- ###############################################################################
- @lm.user_loader
- def load_user(user_id):
- """User loader callback for Flask-Login."""
- return User.query.get(int(user_id))
- class RegisterForm(FlaskForm):
- """Registration form."""
- access = SelectField(validators=[Required()],
- choices=[("dm", "demo"),
- ("dm2", "demo2")])
- username = StringField('Username', validators=[Required(), Length(1, 9)])
- password = PasswordField('Password', validators=[Required(), Length(4, 4)])
- password_again = PasswordField('Password again',
- validators=[Required(), EqualTo('password')])
- submit = SubmitField('Register')
- class LoginForm(FlaskForm):
- """Login form."""
- username = StringField('Username', validators=[Required(), Length(1, 9)])
- password = PasswordField('Password', validators=[Required(), Length(4, 4)])
- token = PasswordField('Token', validators=[Required(), Length(6, 6)])
- submit = SubmitField('Login')
- @app.route('/')
- def index():
- return render_template('index.html')
- @app.route('/register', methods=['GET', 'POST'])
- def register():
- """User registration route."""
- if current_user.is_authenticated:
- # if user is logged in we get out of here
- return redirect(url_for('index'))
- form = RegisterForm()
- if form.validate_on_submit():
- user = User.query.filter_by(username=form.username.data).first()
- if user is not None:
- flash('Username already exists.')
- return redirect(url_for('register'))
- # add new user to the database
- user = User(username=form.username.data, password=form.password.data, access=form.access.data)
- db.session.add(user)
- db.session.commit()
- # redirect to the two-factor auth page, passing username in session
- session['username'] = user.username
- return redirect(url_for('two_factor_setup'))
- return render_template('auth/register.html', form=form)
- @app.route('/twofactor')
- def two_factor_setup():
- if 'username' not in session:
- return redirect(url_for('index'))
- user = User.query.filter_by(username=session['username']).first()
- if user is None:
- return redirect(url_for('index'))
- # since this page contains the sensitive qrcode, make sure the browser
- # does not cache it
- return render_template('auth/2fa.html'), 200, {
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
- 'Pragma': 'no-cache',
- 'Expires': '0'}
- @app.route('/qrcode')
- def qrcode():
- if 'username' not in session:
- abort(404)
- user = User.query.filter_by(username=session['username']).first()
- if user is None:
- abort(404)
- # for added security, remove username from session
- del session['username']
- # render qrcode for FreeTOTP
- url = pyqrcode.create(user.get_totp_uri())
- stream = BytesIO()
- url.svg(stream, scale=3)
- return stream.getvalue(), 200, {
- 'Content-Type': 'image/svg+xml',
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
- 'Pragma': 'no-cache',
- 'Expires': '0'}
- @app.route('/login', methods=['GET', 'POST'])
- def login():
- """User login route."""
- if current_user.is_authenticated:
- # if user is logged in we get out of here
- return redirect(url_for('index'))
- form = LoginForm()
- if form.validate_on_submit():
- user = User.query.filter_by(username=form.username.data).first()
- if user is None or not user.verify_password(form.password.data) or
- not user.verify_totp(form.token.data):
- flash('Invalid username, password or token.')
- return redirect(url_for('login'))
- # log user in
- login_user(user)
- flash('You are now logged in!')
- return redirect(url_for('cm_e_11a'))
- return render_template('auth/login.html', form=form)
- @app.route('/logout')
- def logout():
- """User logout route."""
- logout_user()
- return redirect(url_for('index'))
- <h1>Login</h1>
- <form action="/login" method="POST" name="login_user_form">
- <input id="next" name="next" type="hidden" value="">
- <input id="csrf_token" name="csrf_token" type="hidden" value="IjEyNWY4ZjliNmIxZTJjNmM3YmM4YzFlM2U0NWZlYjJlMDEzYThiNWEi.DZnvqw.key_C7NmtQogY7CSpb14sfVDUOQ">
- <p>
- <label for="email">Email Address</label> <input id="email" name="email" type="text" value="">
- </p>
- <p>
- <label for="password">Password</label> <input id="password" name="password" type="password" value="">
- </p>
- <p>
- <label for="remember">Remember Me</label> <input id="remember" name="remember" type="checkbox" value="y">
- </p>
- <p><input id="next" name="next" type="hidden" value=""></p>
- <p><input id="submit" name="submit" type="submit" value="Login"></p>
- </form>
Add Comment
Please, Sign In to add comment