Guest User

Untitled

a guest
Mar 26th, 2018
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.65 KB | None | 0 0
  1. import os
  2. import base64
  3. from io import BytesIO
  4. from flask import Flask, render_template, request, redirect, url_for, flash, session,
  5. abort
  6. from werkzeug.security import generate_password_hash, check_password_hash
  7. from flask_sqlalchemy import SQLAlchemy
  8. from flask_login import LoginManager, UserMixin, login_user, logout_user,
  9. current_user
  10. from flask_bootstrap import Bootstrap
  11. from flask_wtf import FlaskForm
  12. from wtforms import StringField, PasswordField, SubmitField, SelectField
  13. from wtforms.validators import Required, Length, EqualTo
  14. import onetimepass
  15. import pyqrcode
  16. from datetime import datetime, date, time, timedelta
  17. from sqlalchemy import Table, Column, Integer, ForeignKey
  18. from sqlalchemy.orm import relationship
  19. from sqlalchemy.ext.declarative import declarative_base
  20. from flask_security import Security, SQLAlchemyUserDatastore,
  21. UserMixin, RoleMixin, login_required
  22.  
  23. # create application instance
  24. app = Flask(__name__)
  25. app.config.from_object('config')
  26.  
  27. # initialize extensions
  28. bootstrap = Bootstrap(app)
  29. db = SQLAlchemy(app)
  30. lm = LoginManager(app)
  31. Base = declarative_base()
  32.  
  33. # Define models
  34. roles_users = db.Table('roles_users',
  35. db.Column('users_id', db.Integer(), db.ForeignKey('users.id')),
  36. db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
  37.  
  38. class Role(db.Model, RoleMixin):
  39. id = db.Column(db.Integer(), primary_key=True)
  40. name = db.Column(db.String(80), unique=True)
  41. description = db.Column(db.String(255))
  42.  
  43. class User(UserMixin, db.Model):
  44. """User model."""
  45. __tablename__ = 'users'
  46. id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True)
  47. username = db.Column(db.String(64), unique=True, index=True)
  48. password_hash = db.Column(db.String(128))
  49. otp_secret = db.Column(db.String(16))
  50. access = db.Column(db.String(16))
  51. roles = db.relationship('Role', secondary=roles_users,
  52. backref=db.backref('users', lazy='dynamic'))
  53.  
  54. def __init__(self, **kwargs):
  55. super(User, self).__init__(**kwargs)
  56. if self.otp_secret is None:
  57. # generate a random secret
  58. self.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8')
  59.  
  60. @property
  61. def password(self):
  62. raise AttributeError('password is not a readable attribute')
  63.  
  64. @password.setter
  65. def password(self, password):
  66. self.password_hash = generate_password_hash(password)
  67.  
  68. def verify_password(self, password):
  69. return check_password_hash(self.password_hash, password)
  70.  
  71. def get_totp_uri(self):
  72. return 'otpauth://totp/2FA-Demo:{0}?secret={1}&issuer=2FA-Demo'
  73. .format(self.username, self.otp_secret)
  74.  
  75. def verify_totp(self, token):
  76. return onetimepass.valid_totp(token, self.otp_secret)
  77.  
  78. ################################################################################
  79. user_datastore = SQLAlchemyUserDatastore(db, User, Role)
  80. security = Security(app, user_datastore)
  81. ###############################################################################
  82.  
  83. @lm.user_loader
  84. def load_user(user_id):
  85. """User loader callback for Flask-Login."""
  86. return User.query.get(int(user_id))
  87.  
  88. class RegisterForm(FlaskForm):
  89. """Registration form."""
  90. access = SelectField(validators=[Required()],
  91. choices=[("dm", "demo"),
  92. ("dm2", "demo2")])
  93. username = StringField('Username', validators=[Required(), Length(1, 9)])
  94. password = PasswordField('Password', validators=[Required(), Length(4, 4)])
  95. password_again = PasswordField('Password again',
  96. validators=[Required(), EqualTo('password')])
  97. submit = SubmitField('Register')
  98.  
  99.  
  100. class LoginForm(FlaskForm):
  101. """Login form."""
  102. username = StringField('Username', validators=[Required(), Length(1, 9)])
  103. password = PasswordField('Password', validators=[Required(), Length(4, 4)])
  104. token = PasswordField('Token', validators=[Required(), Length(6, 6)])
  105. submit = SubmitField('Login')
  106.  
  107. @app.route('/')
  108. def index():
  109. return render_template('index.html')
  110.  
  111.  
  112. @app.route('/register', methods=['GET', 'POST'])
  113. def register():
  114. """User registration route."""
  115. if current_user.is_authenticated:
  116. # if user is logged in we get out of here
  117. return redirect(url_for('index'))
  118. form = RegisterForm()
  119. if form.validate_on_submit():
  120. user = User.query.filter_by(username=form.username.data).first()
  121. if user is not None:
  122. flash('Username already exists.')
  123. return redirect(url_for('register'))
  124. # add new user to the database
  125. user = User(username=form.username.data, password=form.password.data, access=form.access.data)
  126. db.session.add(user)
  127. db.session.commit()
  128.  
  129. # redirect to the two-factor auth page, passing username in session
  130. session['username'] = user.username
  131. return redirect(url_for('two_factor_setup'))
  132. return render_template('auth/register.html', form=form)
  133.  
  134.  
  135. @app.route('/twofactor')
  136. def two_factor_setup():
  137. if 'username' not in session:
  138. return redirect(url_for('index'))
  139. user = User.query.filter_by(username=session['username']).first()
  140. if user is None:
  141. return redirect(url_for('index'))
  142. # since this page contains the sensitive qrcode, make sure the browser
  143. # does not cache it
  144. return render_template('auth/2fa.html'), 200, {
  145. 'Cache-Control': 'no-cache, no-store, must-revalidate',
  146. 'Pragma': 'no-cache',
  147. 'Expires': '0'}
  148.  
  149.  
  150. @app.route('/qrcode')
  151. def qrcode():
  152. if 'username' not in session:
  153. abort(404)
  154. user = User.query.filter_by(username=session['username']).first()
  155. if user is None:
  156. abort(404)
  157.  
  158. # for added security, remove username from session
  159. del session['username']
  160.  
  161. # render qrcode for FreeTOTP
  162. url = pyqrcode.create(user.get_totp_uri())
  163. stream = BytesIO()
  164. url.svg(stream, scale=3)
  165. return stream.getvalue(), 200, {
  166. 'Content-Type': 'image/svg+xml',
  167. 'Cache-Control': 'no-cache, no-store, must-revalidate',
  168. 'Pragma': 'no-cache',
  169. 'Expires': '0'}
  170.  
  171.  
  172. @app.route('/login', methods=['GET', 'POST'])
  173. def login():
  174. """User login route."""
  175. if current_user.is_authenticated:
  176. # if user is logged in we get out of here
  177. return redirect(url_for('index'))
  178. form = LoginForm()
  179. if form.validate_on_submit():
  180. user = User.query.filter_by(username=form.username.data).first()
  181. if user is None or not user.verify_password(form.password.data) or
  182. not user.verify_totp(form.token.data):
  183. flash('Invalid username, password or token.')
  184. return redirect(url_for('login'))
  185.  
  186. # log user in
  187. login_user(user)
  188. flash('You are now logged in!')
  189. return redirect(url_for('cm_e_11a'))
  190. return render_template('auth/login.html', form=form)
  191.  
  192.  
  193. @app.route('/logout')
  194. def logout():
  195. """User logout route."""
  196. logout_user()
  197. return redirect(url_for('index'))
  198.  
  199. <h1>Login</h1>
  200. <form action="/login" method="POST" name="login_user_form">
  201. <input id="next" name="next" type="hidden" value="">
  202. <input id="csrf_token" name="csrf_token" type="hidden" value="IjEyNWY4ZjliNmIxZTJjNmM3YmM4YzFlM2U0NWZlYjJlMDEzYThiNWEi.DZnvqw.key_C7NmtQogY7CSpb14sfVDUOQ">
  203.  
  204. <p>
  205. <label for="email">Email Address</label> <input id="email" name="email" type="text" value="">
  206.  
  207. </p>
  208.  
  209.  
  210. <p>
  211. <label for="password">Password</label> <input id="password" name="password" type="password" value="">
  212.  
  213. </p>
  214.  
  215.  
  216. <p>
  217. <label for="remember">Remember Me</label> <input id="remember" name="remember" type="checkbox" value="y">
  218.  
  219. </p>
  220.  
  221.  
  222. <p><input id="next" name="next" type="hidden" value=""></p>
  223.  
  224.  
  225. <p><input id="submit" name="submit" type="submit" value="Login"></p>
  226.  
  227. </form>
Add Comment
Please, Sign In to add comment