Compare commits

...

4 Commits

Author SHA1 Message Date
50865a6619 add aiohttp app middleware reference 2019-10-17 13:39:36 -04:00
4b5170d6d9 only allow activated users in 2019-10-17 13:39:14 -04:00
7ed42e017e submit user perms 2019-10-17 13:38:40 -04:00
c0df27cf96 route declaration scheme 2019-10-17 13:37:35 -04:00
5 changed files with 100 additions and 17 deletions

10
auth.py
View File

@ -73,7 +73,7 @@ def auth_required(func):
return wrapper return wrapper
@routes.post(config.url_prefix + '/register/begin', name='register_begin') @routes.post('/register/begin', name='register_begin')
@auth_required @auth_required
async def register_begin(request): async def register_begin(request):
user_id = request['session']['id'] user_id = request['session']['id']
@ -96,7 +96,7 @@ async def register_begin(request):
return resp return resp
@routes.post(config.url_prefix + '/register/complete',name='register_complete') @routes.post('/register/complete',name='register_complete')
@auth_required @auth_required
async def register_complete(request): async def register_complete(request):
user_id = request['session']['id'] user_id = request['session']['id']
@ -135,8 +135,7 @@ async def register_complete(request):
return resp return resp
@routes.post(config.url_prefix + '/authenticate/begin', @routes.post('/authenticate/begin', name='authenticate_begin')
name='authenticate_begin')
async def authenticate_begin(request): async def authenticate_begin(request):
user_id = int(request.cookies.get('userid')) user_id = int(request.cookies.get('userid'))
if not user_id: if not user_id:
@ -156,8 +155,7 @@ async def authenticate_begin(request):
return resp return resp
@routes.post(config.url_prefix + '/authenticate/complete', @routes.post('/authenticate/complete', name='authenticate_complete')
name='authenticate_complete')
async def authenticate_complete(request): async def authenticate_complete(request):
user_id = int(request.cookies.get('userid')) user_id = int(request.cookies.get('userid'))

View File

@ -23,8 +23,8 @@ import config
uvloop.install() uvloop.install()
routes = web.RouteTableDef() routes = web.RouteTableDef()
@routes.get(config.url_prefix + '/', name='index') @routes.get('/', name='index')
@routes.post(config.url_prefix + '/', name='index') @routes.post('/', name='index')
@auth.auth_required @auth.auth_required
async def index(request): async def index(request):
"""The index page.""" """The index page."""
@ -77,8 +77,8 @@ async def index(request):
return render_template("index.html", request, locals()) return render_template("index.html", request, locals())
@routes.get(config.url_prefix + '/login', name='login') @routes.get('/login', name='login')
@routes.post(config.url_prefix + '/login', name='login') @routes.post('/login', name='login')
async def login(request): async def login(request):
"""Handle login.""" """Handle login."""
login_failed = False login_failed = False
@ -91,7 +91,7 @@ async def login(request):
async with request.app['pool'].acquire() as conn: async with request.app['pool'].acquire() as conn:
user_info = await conn.fetchrow( user_info = await conn.fetchrow(
"SELECT * FROM user_info WHERE username = $1", "SELECT * FROM user_info WHERE username = $1 AND active = TRUE",
username) username)
if user_info: if user_info:
has_cred = await conn.fetchrow( has_cred = await conn.fetchrow(
@ -147,8 +147,8 @@ async def login(request):
return render_template("login.html", request, locals()) return render_template("login.html", request, locals())
@routes.get(config.url_prefix + '/register', name='register') @routes.get('/register', name='register')
@routes.post(config.url_prefix + '/register', name='register') @routes.post('/register', name='register')
async def register(request): async def register(request):
"""Register new accounts.""" """Register new accounts."""
confirm_token = request.query.get('confirm') confirm_token = request.query.get('confirm')
@ -208,7 +208,7 @@ async def register(request):
return render_template("register_result.html", request, locals()) return render_template("register_result.html", request, locals())
@routes.get(config.url_prefix + '/add_key', name='add_key') @routes.get('/add_key', name='add_key')
@auth.auth_required @auth.auth_required
async def add_key(request): async def add_key(request):
"""Add a new security key.""" """Add a new security key."""
@ -216,7 +216,7 @@ async def add_key(request):
return render_template("register_key.html", request, locals()) return render_template("register_key.html", request, locals())
@routes.get(config.url_prefix + '/get_session', name='get_session') @routes.get('/get_session', name='get_session')
async def get_session(request): async def get_session(request):
"""Returns a user's application session.""" """Returns a user's application session."""
# TODO: only allow LAN IPs # TODO: only allow LAN IPs
@ -284,7 +284,7 @@ async def get_session(request):
return web.json_response(error) return web.json_response(error)
@routes.post(config.url_prefix + '/set_session', name='set_session') @routes.post('/set_session', name='set_session')
async def set_session(request): async def set_session(request):
"""Allows an application to set a user app session.""" """Allows an application to set a user app session."""
# TODO: only allow LAN IPs # TODO: only allow LAN IPs
@ -339,6 +339,9 @@ async def init_app():
app.router.add_routes(routes) app.router.add_routes(routes)
app.router.add_routes(auth.routes) app.router.add_routes(auth.routes)
app_wrap = web.Application()
app_wrap.add_subapp(config.url_prefix, app)
return app return app
if __name__ == "__main__": if __name__ == "__main__":

61
buckler_aiohttp.py Normal file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""
Session interface middlewares to integrate the aiohttp app with Buckler.
"""
import json
from datetime import datetime
import aiohttp
from aiohttp import web
import config
@web.middleware
async def buckler_session(request, handler):
"""
Verifies the user with the configured Buckler app and retrieves any
session data they may have. Redirects them to the login page otherwise.
"""
user_id = request.cookies.get('userid')
user_sid = request.cookies.get('session')
url = config.buckler['url'] + '/get_session'
params = {
'app_id': config.buckler['app_id'],
'app_key': config.buckler['app_key'],
'userid': user_id,
'session': user_sid
}
async with aiohttp.ClientSession() as session:
async with session.get(url, params=params) as resp:
data = await resp.json()
if data.get('error'):
raise web.HTTPFound(location=config.buckler['login_url'])
request['session'] = data['session_data']
request['meta'] = data['meta']
resp = await handler(request)
if request['session'] != data['session_data']: # session data modified
url = config.buckler['url'] + '/set_session'
data = json.dumps(request['session'])
session.post(url, params=params, data=data) # TODO: error handle?
last_used = datetime.fromisoformat(request['meta']['last_used'])
now = datetime.now(last_used.tzinfo)
delta = now - last_used
if delta.seconds > 600:
resp.set_cookie(
'userid',
user_id,
max_age=30*24*60*60,
secure=True,
httponly=True)
resp.set_cookie(
'session',
user_sid,
max_age=30*24*60*60,
secure=True,
httponly=True)
return resp

View File

@ -37,3 +37,22 @@ function perm_change(row) {
} }
console.log("perms_changed = " + perms_changed); console.log("perms_changed = " + perms_changed);
} }
function submit_user_perms(row) {
let row_perms = {};
for (let child of row.children) {
if (child.firstChild.type == "checkbox") {
if (child.firstChild.checked) {
row_perms[child.firstChild.dataset.appName] = true;
} else {
row_perms[child.firstChild.dataset.appName] = false;
}
}
}
console.log(row_perms);
fetch(window.location.pathname, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: row_perms
});
}

View File

@ -32,6 +32,7 @@
<section> <section>
<h2>Admin Panel</h2> <h2>Admin Panel</h2>
<article style="display: none;"> <article style="display: none;">
<hr>
<section class="sub_section"> <section class="sub_section">
<h3>User Permissions</h3> <h3>User Permissions</h3>
<article style="display: none;"> <article style="display: none;">
@ -53,13 +54,14 @@
{% for name, value in values.items() %} {% for name, value in values.items() %}
<td><input aria-label="{{ username }}-{{ name }}" data-app-name={{ name }} type="checkbox" onchange="perm_change(this.parentElement.parentElement)"{% if value %} checked{% endif %}></td> <td><input aria-label="{{ username }}-{{ name }}" data-app-name={{ name }} type="checkbox" onchange="perm_change(this.parentElement.parentElement)"{% if value %} checked{% endif %}></td>
{% endfor %} {% endfor %}
<td><input type="submit"></td> <td><input type="submit" value="Save" onclick="submit_user_perms(this.parentElement.parentElement)"></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</article> </article>
</section> </section>
<br>
<section class="sub_section"> <section class="sub_section">
<h3>Invite New User</h3> <h3>Invite New User</h3>
<article style="display: none;"> <article style="display: none;">