Advertisement
Guest User

Untitled

a guest
Oct 28th, 2018
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.97 KB | None | 0 0
  1. import hashlib
  2. import json
  3. import random
  4. import os
  5. import sys
  6. from datetime import datetime, timedelta
  7.  
  8. import flask
  9. from authlib.specs.rfc7519 import jwt
  10. from authlib.specs.rfc7515 import BadSignatureError
  11.  
  12. app = flask.Flask(__name__)
  13.  
  14. private_key_file = os.environ.get('AUTH_PRIVATE_KEY_FILE')
  15. public_key_file = os.environ.get('AUTH_PUBLIC_KEY_FILE')
  16.  
  17. auth_domain = os.environ.get('AUTH_DOMAIN', 'localhost')
  18. auth_info_file = os.environ.get('AUTH_INFO_FILE')
  19.  
  20. assert private_key_file, 'You should pass secret via AUTH_PRIVATE_KEY_FILE environment variable'
  21. assert public_key_file, 'You should pass secret via AUTH_PUBLIC_KEY_FILE environment variable'
  22.  
  23. assert auth_info_file, 'You should pass auth file via AUTH_INFO_FILE environment variable'
  24.  
  25. with open(private_key_file) as fp:
  26.     private_key = fp.read()
  27.  
  28. with open(public_key_file) as fp:
  29.     public_key = fp.read()
  30.  
  31. with open(auth_info_file) as fp:
  32.     auth_info_data = json.load(fp)
  33.  
  34.  
  35. @app.before_request
  36. def csrf_protection():
  37.     if flask.request.method in {'GET', 'HEAD', 'OPTIONS'}:
  38.         return
  39.  
  40.     if flask.request.path == flask.url_for('get_auth_info'):
  41.         return
  42.  
  43.     expected_csrf_token = flask.request.cookies.get('CSRF_TOKEN')
  44.     actual_csrf_token = flask.request.form.get('CSRF_TOKEN')
  45.  
  46.     if not expected_csrf_token or actual_csrf_token != expected_csrf_token:
  47.         flask.abort(flask.Response('No CSRF token', status=403))
  48.  
  49.  
  50. @app.route('/')
  51. def index():
  52.     return_path = flask.request.args.get('return-path', flask.url_for('index'))
  53.  
  54.     if is_authenticated():
  55.         return make_template_response('user-panel.html', return_path=return_path)
  56.  
  57.     return make_template_response('auth-form.html', return_path=return_path)
  58.  
  59.  
  60. @app.route('/login', methods=('POST',))
  61. def login():
  62.     login = flask.request.form.get('login')
  63.     password = flask.request.form.get('password')
  64.     return_path = flask.request.form.get('return-path', flask.url_for('index'))
  65.  
  66.     if not login or not password:
  67.         return flask.abort(flask.Response('No auth info', status=400))
  68.  
  69.     expected_password_hash = auth_info_data.get(login)
  70.  
  71.     if not expected_password_hash:
  72.         return flask.abort(flask.Response('Wrong login', status=403))
  73.  
  74.     hasher = hashlib.sha512()
  75.     hasher.update(password.encode('utf-8'))
  76.     actual_password_hash = hasher.hexdigest()
  77.  
  78.     if actual_password_hash != expected_password_hash:
  79.         return flask.abort(flask.Response('Wrong password', status=403))
  80.  
  81.     header = {'alg': 'RS256'}
  82.     payload = {'login': login}
  83.  
  84.     auth_token = jwt.encode(header, payload, private_key)
  85.     expires = datetime.now() + timedelta(days=30)
  86.     domain = auth_domain if not app.debug else None
  87.  
  88.     resp = flask.redirect(return_path, code=302)
  89.     resp.set_cookie('AUTH_TOKEN', auth_token, expires=expires, domain=domain, httponly=True, secure=not app.debug)
  90.  
  91.     return make_response(resp)
  92.  
  93.  
  94. @app.route('/logout', methods=('POST',))
  95. def logout():
  96.     return_path = flask.request.form.get('return-path', flask.url_for('index'))
  97.  
  98.     auth_token = ''
  99.     expires = datetime.now() - timedelta(days=30)
  100.     domain = auth_domain if not app.debug else None
  101.  
  102.     resp = flask.redirect(return_path, code=302)
  103.     resp.set_cookie('AUTH_TOKEN', auth_token, expires=expires,
  104.         domain=domain, httponly=True, secure=not app.debug)
  105.  
  106.     return make_response(resp)
  107.  
  108.  
  109. @app.route('/get-auth-info', methods=('POST',))
  110. def get_auth_info():
  111.     auth_info = extract_auth_info(flask.request.form.get('auth-token'))
  112.     return json.dumps(auth_info)
  113.  
  114.  
  115. @app.route('/get-public-key')
  116. def get_public_key():
  117.     return public_key
  118.  
  119.  
  120. @app.route('/get-token', methods=('POST',))
  121. def get_token():
  122.     auth_token = flask.request.cookies.get('AUTH_TOKEN')
  123.     if not auth_token:
  124.         return flask.abort(flask.Response('No token', status=400))
  125.  
  126.     return make_template_response('show-token.html', auth_token=auth_token)
  127.  
  128.  
  129. def is_authenticated():
  130.     auth_token = flask.request.cookies.get('AUTH_TOKEN')
  131.     if not auth_token:
  132.         return False
  133.  
  134.     auth_info = extract_auth_info(auth_token)
  135.     return bool(auth_info)
  136.  
  137.  
  138. def extract_auth_info(auth_token=None):
  139.     if not auth_token:
  140.         auth_token = flask.request.cookies.get('AUTH_TOKEN')
  141.  
  142.     try:
  143.         claims = jwt.decode(auth_token, public_key)
  144.     except BadSignatureError:
  145.         return False
  146.  
  147.     return dict(claims)
  148.  
  149.  
  150. def make_template_response(template, **kwargs):
  151.     resp = make_response()
  152.     resp.response.append(flask.render_template(template, **kwargs))
  153.  
  154.     return resp
  155.  
  156.  
  157. def make_response(base_resp=None):
  158.     if not base_resp:
  159.         base_resp = flask.Response()
  160.  
  161.     csrf_token = flask.request.cookies.get('CSRF_TOKEN')
  162.     if not csrf_token:
  163.         csrf_token = hex(random.randrange(0, sys.maxsize))
  164.         base_resp.set_cookie('CSRF_TOKEN', csrf_token,
  165.             httponly=True, secure=not app.debug)
  166.  
  167.     app.jinja_env.globals['csrf_token'] = csrf_token
  168.  
  169.     return base_resp
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement