Basic Reddit authentication flow
This commit is contained in:
parent
bf1b8cee09
commit
c70dabcbe1
@ -50,6 +50,28 @@ if 'EOSWEB_SETTINGS' in os.environ:
|
||||
# Connect to database
|
||||
db_connect(app.config['DB_NAME'], app.config['MONGO_URI'])
|
||||
|
||||
# Make Flask's serialisation, e.g. for sessions, EosObject aware
|
||||
class EosObjectJSONEncoder(flask.json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj, EosObject):
|
||||
return EosObject.serialise_and_wrap(obj)
|
||||
return super().default(obj)
|
||||
class EosObjectJSONDecoder(flask.json.JSONDecoder):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.super_object_hook = kwargs.get('object_hook', None)
|
||||
kwargs['object_hook'] = self.my_object_hook
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def my_object_hook(self, val):
|
||||
if 'type' in val:
|
||||
if val['type'] in EosObject.objects:
|
||||
return EosObject.deserialise_and_unwrap(val)
|
||||
if self.super_object_hook:
|
||||
return self.super_object_hook(val)
|
||||
return val
|
||||
app.json_encoder = EosObjectJSONEncoder
|
||||
app.json_decoder = EosObjectJSONDecoder
|
||||
|
||||
@app.cli.command('test')
|
||||
@click.option('--prefix', default=None)
|
||||
@click.option('--lang', default=None)
|
||||
@ -123,6 +145,8 @@ def count_test_election():
|
||||
def inject_globals():
|
||||
return {'eos': eos, 'eosweb': eosweb, 'SHA256': eos.core.hashing.SHA256}
|
||||
|
||||
# === Views ===
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('index.html')
|
||||
@ -197,6 +221,35 @@ def election_api_cast_vote(election):
|
||||
'vote': EosObject.serialise_and_wrap(vote)
|
||||
}), mimetype='application/json')
|
||||
|
||||
@app.route('/debug')
|
||||
def debug():
|
||||
assert False
|
||||
|
||||
@app.route('/auth/login')
|
||||
def login():
|
||||
return flask.render_template('auth/login.html')
|
||||
|
||||
@app.route('/auth/logout')
|
||||
def logout():
|
||||
flask.session['user'] = None
|
||||
#return flask.redirect(flask.request.args['next'] if 'next' in flask.request.args else '/')
|
||||
# I feel like there's some kind of exploit here, so we'll leave this for now
|
||||
return flask.redirect('/')
|
||||
|
||||
@app.route('/auth/login_complete')
|
||||
def login_complete():
|
||||
return flask.render_template('auth/login_complete.html')
|
||||
|
||||
@app.route('/auth/login_cancelled')
|
||||
def login_cancelled():
|
||||
return flask.render_template('auth/login_cancelled.html')
|
||||
|
||||
# === Apps ===
|
||||
|
||||
for app_name in app.config['APPS']:
|
||||
app_main = importlib.import_module(app_name + '.main')
|
||||
app_main.main(app)
|
||||
|
||||
# === Model-Views ===
|
||||
|
||||
model_view_map = {}
|
||||
|
47
eosweb/core/templates/auth/login.html
Normal file
47
eosweb/core/templates/auth/login.html
Normal file
@ -0,0 +1,47 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{#
|
||||
Eos - Verifiable elections
|
||||
Copyright © 2017 RunasSudo (Yingtong Li)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if session.user %}
|
||||
<p>You are currently logged in as {{ session.user.username }}. Please select an option from the list below to switch accounts.</p>
|
||||
{% else %}
|
||||
<p>You are not currently logged in. Please select an option from the list below to log in.</p>
|
||||
{% endif %}
|
||||
<ul>
|
||||
{% for auth_method in eosweb.app.config['AUTH_METHODS'] %}
|
||||
<li><a href="/auth/{{ auth_method[0] }}/login" target="_blank" onclick="login(this);return false;">{{ auth_method[1] }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block basecontent %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
function login(el) {
|
||||
window.open(el.getAttribute("href"), "eos_login_window", "width=400,height=600");
|
||||
}
|
||||
|
||||
function callback_complete() {
|
||||
window.location = "/";
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
40
eosweb/core/templates/auth/login_complete.html
Normal file
40
eosweb/core/templates/auth/login_complete.html
Normal file
@ -0,0 +1,40 @@
|
||||
{% extends 'semantic_base.html' %}
|
||||
|
||||
{#
|
||||
Eos - Verifiable elections
|
||||
Copyright © 2017 RunasSudo (Yingtong Li)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block basecontent %}
|
||||
<div class="ui middle aligned center aligned grid" style="height: 100%;">
|
||||
<div class="column" style="max-width: 400px;">
|
||||
<div class="ui success message">
|
||||
<div class="header">Log in successful</div>
|
||||
<p>You have successfully logged in to your account.</p>
|
||||
<p>You may now close this window and return to your previous page.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.setTimeout(function() {
|
||||
window.close();
|
||||
window.opener.callback_complete();
|
||||
}, 1000);
|
||||
</script>
|
||||
{% endblock %}
|
@ -26,7 +26,16 @@
|
||||
<div class="ui fixed inverted menu" style="margin-right: 1.5em;">
|
||||
<div class="ui container">
|
||||
<a href="/" class="header item">Eos Voting</a>
|
||||
<a href="#" class="item right">Log in</a>
|
||||
{% if session.user %}
|
||||
<div class="ui simple dropdown item right">
|
||||
{{ session.user.username }} <i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<a href="{{ url_for('logout') }}?next={{ request.full_path|urlencode }}" class="item">Log out</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="{{ url_for('login') }}" class="item right">Log in</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui main text container" id="main_container">
|
||||
|
0
eosweb/redditauth/__init__.py
Normal file
0
eosweb/redditauth/__init__.py
Normal file
68
eosweb/redditauth/main.py
Normal file
68
eosweb/redditauth/main.py
Normal file
@ -0,0 +1,68 @@
|
||||
# Eos - Verifiable elections
|
||||
# Copyright © 2017 RunasSudo (Yingtong Li)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from flask_oauthlib.client import OAuth
|
||||
|
||||
import flask
|
||||
|
||||
from eos.core.objects import *
|
||||
|
||||
import base64
|
||||
import uuid
|
||||
|
||||
class RedditUser(DocumentObject):
|
||||
oauth_token = StringField(is_protected=True)
|
||||
username = StringField()
|
||||
|
||||
def main(app):
|
||||
oauth = OAuth()
|
||||
reddit = oauth.remote_app('Reddit',
|
||||
request_token_url=None,
|
||||
authorize_url='https://www.reddit.com/api/v1/authorize.compact',
|
||||
request_token_params={'duration': 'temporary', 'scope': 'identity'},
|
||||
access_token_url='https://www.reddit.com/api/v1/access_token',
|
||||
access_token_method='POST',
|
||||
access_token_headers={
|
||||
'Authorization': 'Basic ' + base64.b64encode('{}:{}'.format(app.config['REDDIT_OAUTH_CLIENT_ID'], app.config['REDDIT_OAUTH_CLIENT_SECRET']).encode('ascii')).decode('ascii'),
|
||||
'User-Agent': app.config['REDDIT_USER_AGENT']
|
||||
},
|
||||
consumer_key=app.config['REDDIT_OAUTH_CLIENT_ID'],
|
||||
consumer_secret=app.config['REDDIT_OAUTH_CLIENT_SECRET']
|
||||
)
|
||||
|
||||
@app.route('/auth/reddit/login')
|
||||
def reddit_login():
|
||||
return reddit.authorize(callback=app.config['BASE_URI'] + flask.url_for('reddit_oauth_authorized'), state=uuid.uuid4())
|
||||
|
||||
@reddit.tokengetter
|
||||
def get_reddit_oauth_token():
|
||||
return (flask.session.get('user').oauth_token, '')
|
||||
|
||||
@app.route('/auth/reddit/oauth_callback')
|
||||
def reddit_oauth_authorized():
|
||||
resp = reddit.authorized_response()
|
||||
if resp is None:
|
||||
# Request denied
|
||||
return flask.redirect(flask.url_for('login_cancelled'))
|
||||
|
||||
user = RedditUser()
|
||||
user.oauth_token = resp['access_token']
|
||||
flask.session['user'] = user
|
||||
|
||||
me = reddit.get('https://oauth.reddit.com/api/v1/me')
|
||||
user.username = me.data['name']
|
||||
|
||||
return flask.redirect(flask.url_for('login_complete'))
|
20
eosweb/redditauth/settings.py
Normal file
20
eosweb/redditauth/settings.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Eos - Verifiable elections
|
||||
# Copyright © 2017 RunasSudo (Yingtong Li)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
REDDIT_OAUTH_CLIENT_ID = 'xxxxxxxxxxxxxx'
|
||||
REDDIT_OAUTH_CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
|
||||
REDDIT_USER_AGENT = 'FIXME'
|
Loading…
Reference in New Issue
Block a user