diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..04eab79 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,3 @@ +password +secret +secret.json diff --git a/src/auth/__init__.py b/src/auth/__init__.py deleted file mode 100644 index 4c06cdc..0000000 --- a/src/auth/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from auth import * diff --git a/src/auth/auth.py b/src/auth/auth.py deleted file mode 100644 index f85a724..0000000 --- a/src/auth/auth.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/python - -from ..utils import authentication_core #as authentication -from ..utils import authorization_core #as authorization - -# Setup flask basics. -from flask import Flask, render_template, make_response, request -app = Flask(__name__) - -# TODO: Remove in production? DO NOT PRINT TOKEN FOR FUCKS SAKE. -@app.route('/') -def test(): - username = request.cookies.get('username') - token = request.cookies.get('token') - return render_template( 'test.html', username = username, token = token ) - -@app.route('/login', methods=['GET', 'POST']) -def login(): - if request.method == 'POST': - username = request.form['username'] - password = request.form['password'] - try: - token = authentication_core.authenticate( username, password ) - resp = make_response( render_template( 'logged_in.html', username = username ) ) - resp.set_cookie( 'username', username ) - resp.set_cookie( 'token', token ) - return resp - except authentication_core.AuthenticationError: - return "Authentication Error" - else: - return render_template( 'login.html' ) - -@app.route('/logout', methods=['GET', 'POST']) -def logout(): - username = request.cookies.get('username') - token = request.cookies.get('token') - try: - authentication_core.invalidate_token( username, token ) - resp = make_response( render_template( 'logged_out.html', username = username ) ) - resp.set_cookie( 'username', '' ) - resp.set_cookie( 'token', '' ) - return resp - except authentication_core.AuthenticationError: - return "Authentication Error" - -# TODO: Remove in production. -@app.route('/authtest') -def authtest(): - username = request.cookies.get('username') - token = request.cookies.get('token') - - @authorization_core.restricted( "simmons-tech" ) - def super_secret(): - return "Welcome, Simmons Tech Member " + username + "!" - - try: - return super_secret( username, token ) - except authorization_core.AuthorizationError: - return "Nice try " + username + ". No bits for you." - - -if __name__ == "__main__": - app.debug = True # TODO: Remove in production. - app.run() diff --git a/src/auth/templates/logged_in.html b/src/auth/templates/logged_in.html deleted file mode 100644 index 6d00669..0000000 --- a/src/auth/templates/logged_in.html +++ /dev/null @@ -1,3 +0,0 @@ -You've been logged in {{ username }}!
- -testpage diff --git a/src/auth/templates/logged_out.html b/src/auth/templates/logged_out.html deleted file mode 100644 index 599c9b1..0000000 --- a/src/auth/templates/logged_out.html +++ /dev/null @@ -1,3 +0,0 @@ -You've been logged out {{ username }}!
- -testpage diff --git a/src/auth/templates/test.html b/src/auth/templates/test.html deleted file mode 100644 index 9d8aa87..0000000 --- a/src/auth/templates/test.html +++ /dev/null @@ -1,6 +0,0 @@ -Username: {{ username }}
- -Token: {{ token }}
- -login -logout diff --git a/src/dispatch.py b/src/dispatch.py index 220c8d2..bd26380 100644 --- a/src/dispatch.py +++ b/src/dispatch.py @@ -1,7 +1,7 @@ from flask import Flask from werkzeug.wsgi import DispatcherMiddleware -from auth import app as auth_app +from login import app as login_app from buses import app as buses_app from laundry import app as laundry_app from packages import app as packages_app @@ -9,13 +9,14 @@ from profile import app as profile_app from rooming_assignment import app as rooming_assignment_app from rooms import app as rooms_app +from groups import app as groups_app app = Flask(__name__) app.wsgi_app = DispatcherMiddleware( app.wsgi_app, { - '/auth': auth_app, + '/login': login_app, '/buses': buses_app, '/laundry': laundry_app, '/packages': packages_app, @@ -23,6 +24,7 @@ '/profile': profile_app, # TODO: rename to profiles? '/rooming_assignment': rooming_assignment_app, # TODO: rename to rooming_assignments? '/rooms': rooms_app, + '/groups': groups_app, }) app.run() diff --git a/src/groups/__init__.py b/src/groups/__init__.py new file mode 100644 index 0000000..5d2cbc8 --- /dev/null +++ b/src/groups/__init__.py @@ -0,0 +1 @@ +from groups import * diff --git a/src/groups/groups.py b/src/groups/groups.py new file mode 100644 index 0000000..b9ba5b6 --- /dev/null +++ b/src/groups/groups.py @@ -0,0 +1,21 @@ +#!/usr/bin/python + +# Setup flask basics. +from flask import Flask, jsonify +from ..utils import authorization_core as authcore + +app = Flask(__name__) + +@app.route('/') +def serve_groups(): + return jsonify(groupnames = authcore.get_groupnames()) + +@app.route('//') +def serve_members( groupname ): + return jsonify( + groupname = groupname, + members = list(authcore.members(groupname))) + +if __name__ == "__main__": + app.debug = True # TODO: Remove in production. + app.run() diff --git a/src/login/__init__.py b/src/login/__init__.py new file mode 100644 index 0000000..3a6230b --- /dev/null +++ b/src/login/__init__.py @@ -0,0 +1 @@ +from login import * diff --git a/src/login/login.py b/src/login/login.py new file mode 100644 index 0000000..c9d618b --- /dev/null +++ b/src/login/login.py @@ -0,0 +1,95 @@ +#!/usr/bin/python + +from ..utils import authentication_core +from ..utils import authorization_core + +import binascii +import os + +# Setup flask basics. +from flask import Flask, render_template, make_response, request, jsonify, redirect +app = Flask(__name__) + +### SESSION LOOKUP AND STORE ### + +# TODO: Do not use an in memory store. Make a LOGIN_SESSION Database. + +session_cache = {} + +def register_session(redirect, state, domain): + session_id = binascii.hexlify(os.urandom(16)) # Hex Encoding for URL Saftey. + session_cache[session_id] = (redirect, state, domain) + return session_id + +# Deletes the session and returns it. +def recall_session( session_id ): + result = session_cache[session_id] + del session_cache[session_id] + return result + +################################ + +def domain_from_redirect( redirect ): + #TODO: Use URL Parse. + if 'mit.edu' in redirect: + return '.mit.edu' + return '' + +@app.route('/') +def login_page(): + # Required args. + redirect = request.args.get('redirect', None) + if redirect == None: + return "500: Must Provide Redirect (i.e. login/?redirect=simmons.mit.edu/directory)" + # Optional args. + state = request.args.get('state', '') + domain = request.args.get('domain', domain_from_redirect(redirect)) + + # TODO: Generate session key? Don't expose redirect, state, domain. + session_id = register_session(redirect, state, domain) + + # Lot of work in login.html. + return render_template( 'login.html', session_id = session_id ) + +@app.route('/handler', methods=['POST']) +def login_handler(): + # TODO: This is only the local case, reflect that. + session_id = request.args.get('session_id') + session_id = session_id.strip() # TODO: Check if this is needed. It shouldn't be, but I'm paranoid about trailing newlines or something. + username = request.form['username'] + password = request.form['password'] # TODO: This is horribly insecure... Use a burner key with SRP. + redirect_link, state, domain = recall_session( session_id ) # TODO: Handle case where session_id not in cache. + try: + token = authentication_core.authenticate( username, password ) + response = make_response(redirect(redirect_link)) + response.set_cookie( 'username', username ) + response.set_cookie( 'token', token ) + return response + except authentication_core.AuthenticationError: + return "500: Authentication Error" + +# TODO: Add redirect to this, default to login page. +@app.route('/invalidate', methods=['GET','POST']) +def invalidate_token(): + username = request.cookies.get('username') + token = request.cookies.get('token') + redirect_link = request.args.get('redirect', '/login/?redirect=http://simmons.mit.edu') + try: + authentication_core.invalidate_token( username, token ) + return make_response(redirect(redirect_link)) + except authentication_core.AuthenticationError: + return "500: Authentication Error" + +@app.route('/check') +def check_token(): + try: + username = request.cookies.get('username') + token = request.cookies.get('token') + authentication_core.validate_token(username, token) + return jsonify(response='200', username=username) + except: # TODO: Restrict what this catches. + return jsonify(response='401') + +if __name__ == "__main__": + app.debug = True # TODO: Remove in production. + app.run() diff --git a/src/auth/templates/login.html b/src/login/templates/login.html similarity index 66% rename from src/auth/templates/login.html rename to src/login/templates/login.html index 692962e..b180927 100644 --- a/src/auth/templates/login.html +++ b/src/login/templates/login.html @@ -1,6 +1,5 @@ -
+ Username:
Password:

-testpage diff --git a/src/utils/authentication_core/authentication_core.py b/src/utils/authentication_core/authentication_core.py index e3814f9..028f5a1 100644 --- a/src/utils/authentication_core/authentication_core.py +++ b/src/utils/authentication_core/authentication_core.py @@ -16,7 +16,6 @@ # Util imports from .. import db - # Authcore imports import HMAC from authentication_exceptions import * diff --git a/src/utils/authorization_core/authorization_core.py b/src/utils/authorization_core/authorization_core.py index d0e00b7..7d7b02f 100644 --- a/src/utils/authorization_core/authorization_core.py +++ b/src/utils/authorization_core/authorization_core.py @@ -20,6 +20,12 @@ # Local imports from authorization_exceptions import * +def get_groupnames(): + group_db = db.init('group') + groups = [ group.groupname for group in group_db.query(db.Group) ] + return groups + # TODO: Close db? + def is_group( name ): group_db = db.init('group') group = group_db.query(db.Group).get( name ) diff --git a/src/utils/db/db/user/user.db b/src/utils/db/db/user/user.db index 99fe14a..8ba97af 100644 Binary files a/src/utils/db/db/user/user.db and b/src/utils/db/db/user/user.db differ diff --git a/stubgen/apis.yaml b/stubgen/apis.yaml index 840e916..6700b0b 100644 --- a/stubgen/apis.yaml +++ b/stubgen/apis.yaml @@ -2,6 +2,14 @@ # This method is used to generate stubs for both local and remote use on both clients and providers. --- +- name: login + desc: Aux. methods for supporting the Simmons SSO System. + path: "login/" + fxns: + - name: check + desc: Checks if the user is logged in. If so, will provide their username. + args: [] + path: "check" - name: rooms desc: Provides data about the physical characteristics of Simmons rooms. path: "rooms/" diff --git a/stubgen/stubs/javascript/simmons-api.js b/stubgen/stubs/javascript/simmons-api.js index b72f53f..3d57417 100644 --- a/stubgen/stubs/javascript/simmons-api.js +++ b/stubgen/stubs/javascript/simmons-api.js @@ -11,6 +11,16 @@ this.RPC_call = function( path, callback ) { } +// Beginning stubs for login: +// Aux. methods for supporting the Simmons SSO System. +this.login = { + + // Checks if the user is logged in. If so, will provide their username. + check: function( callback ) { + return RPC_call( "login/check", callback ); + }, +}; // End of stubs for login + // Beginning stubs for rooms: // Provides data about the physical characteristics of Simmons rooms. this.rooms = { diff --git a/stubgen/stubs/python/simmons_api/__init__.py b/stubgen/stubs/python/simmons_api/__init__.py index c79666d..6d11534 100644 --- a/stubgen/stubs/python/simmons_api/__init__.py +++ b/stubgen/stubs/python/simmons_api/__init__.py @@ -4,6 +4,7 @@ # This will ensure that changes are reflected in other # languages stubs. +import login import rooms import rooming_assignment import people diff --git a/stubgen/stubs/python/simmons_api/login.py b/stubgen/stubs/python/simmons_api/login.py new file mode 100644 index 0000000..9b521bb --- /dev/null +++ b/stubgen/stubs/python/simmons_api/login.py @@ -0,0 +1,20 @@ +# SIMMONS API CLIENT STUBS FOR PYTHON +# This code was auto-generated by stubgen.py +# DO NOT EDIT IT BY HAND. Edit apis.yaml instead. +# This will ensure that changes are reflected in other +# languages stubs. + +from __common import * + +### +# Beginning stubs for login: +# Aux. methods for supporting the Simmons SSO System. +### + +# Checks if the user is logged in. If so, will provide their username. +def check( ): + return RPC_call( "login/check" ) + +### +# End of stubs for login +### \ No newline at end of file