Add session creation and handling

This commit adds setting the content of the current user from the
session cookie the user sends back and forth. That means we can actually
pull out the session data for use when handling requests. We can also
create new sessions and set up the session cookie
This commit is contained in:
Eli Ribble 2016-05-17 14:16:14 -06:00
parent db066e18d7
commit d83312234b
5 changed files with 121 additions and 5 deletions

36
vanth/api/session.py Normal file
View File

@ -0,0 +1,36 @@
import json
import flask
import sepiida.endpoints
import sepiida.fields
import vanth.auth
import vanth.errors
import vanth.platform.user
import vanth.user
class Session(sepiida.endpoints.APIEndpoint):
ENDPOINT = '/session/'
SIGNATURE = sepiida.fields.JSONObject(s={
'username' : sepiida.fields.String(),
'password' : sepiida.fields.String(methods=['POST']),
})
@staticmethod
def post(payload):
user = vanth.platform.user.by_credentials(payload['username'], payload['password'])
if not user:
raise vanth.errors.InvalidCredentials()
vanth.auth.set_session(user)
@staticmethod
def get(uuid): # pylint: disable=unused-argument
user = vanth.auth.current_user()
del user['password']
if not user:
raise vanth.errors.ResourceDoesNotExist("You are not currently authenticated and therefore do not have a session")
return user
def list(self):
payload = self.get(None)
return flask.make_response(json.dumps(payload), 200, {'Content-Type': 'application/json'})

57
vanth/auth.py Normal file
View File

@ -0,0 +1,57 @@
import uuid
import flask
import sepiida.routing
import vanth.platform.user
PUBLIC_ENDPOINTS = [
'session.post',
'about.get',
]
def register_auth_handlers(app):
app.before_request(require_user)
def endpoint():
if flask.request.endpoint and flask.request.method:
return "{}.{}".format(flask.request.endpoint.lower(), flask.request.method.lower())
def require_user():
user = None
if flask.request.method == 'OPTIONS' and 'Access-Control-Request-Method' in flask.request.headers:
return
if not endpoint():
return flask.make_response('Resource not found', 404)
if endpoint() in PUBLIC_ENDPOINTS:
return
if 'user_uri' not in flask.session:
raise vanth.errors.AuthenticationException(
status_code = 403,
error_code = 'unauthorized',
title = 'You must provide a valid session cookie',
)
_, params = sepiida.routing.extract_parameters(flask.current_app, 'GET', flask.session['user_uri'])
user = vanth.platform.user.by_filter({'uuid': [str(params['uuid'])]})
if not user:
raise vanth.errors.AuthenticationException(
status_code = 403,
error_code = 'invalid-user',
title = 'The user tied to your session does not exist. Figure that out',
)
flask.g.current_user = user[0]
def current_user():
return getattr(flask.g, 'current_user', None)
def is_authenticated():
return current_user() is not None
def set_session(user):
flask.session['user_uri'] = user['uri']
flask.session['uuid'] = str(uuid.uuid4())

5
vanth/errors.py Normal file
View File

@ -0,0 +1,5 @@
import sepiida.errors
AuthenticationException = sepiida.errors.api_error(status_code=403, error_code='authentication-exception')
InvalidCredentials = sepiida.errors.api_error(status_code=401, error_code='invalid-credentials')
ResourceDoesNotExist = sepiida.errors.api_error(status_code=404, error_code='resource-does-not-exist')

View File

@ -8,17 +8,32 @@ import sepiida.routing
import vanth.tables
def _to_dict(result):
return {
'username' : result[vanth.tables.User.c.username],
'password' : result[vanth.tables.User.c.password],
'name' : result[vanth.tables.User.c.name],
'uri' : sepiida.routing.uri('user', result[vanth.tables.User.c.uuid]),
}
def by_filter(filters):
engine = chryso.connection.get()
query = vanth.tables.User.select()
query = chryso.queryadapter.map_and_filter(vanth.tables.User, filters, query)
results = engine.execute(query).fetchall()
return [{
'username' : result[vanth.tables.User.c.username],
'password' : result[vanth.tables.User.c.password],
'name' : result[vanth.tables.User.c.name],
} for result in results]
return [_to_dict(result) for result in results]
def by_credentials(username, password):
engine = chryso.connection.get()
query = vanth.tables.User.select().where(vanth.tables.User.c.username == username)
result = engine.execute(query).first()
if not (result and passlib.apps.custom_app_context.verify(password, result[vanth.tables.User.c.password])):
return None
return _to_dict(result)
def create(name, username, password):
engine = chryso.connection.get()

View File

@ -9,6 +9,7 @@ import sepiida.endpoints
import vanth.api.about
import vanth.api.session
import vanth.api.user
import vanth.auth
import vanth.user
EXPOSE_HEADERS = [
@ -56,6 +57,7 @@ def create_app(config):
supports_credentials=True,
expose_headers=EXPOSE_HEADERS,
)
vanth.auth.register_auth_handlers(app)
app.route('/', methods=['GET'])(index)
app.route('/login/', methods=['GET', 'POST', 'DELETE'])(login)
@ -63,5 +65,6 @@ def create_app(config):
sepiida.endpoints.add_resource(app, vanth.api.about.About, endpoint='about')
sepiida.endpoints.add_resource(app, vanth.api.user.User, endpoint='user')
sepiida.endpoints.add_resource(app, vanth.api.session.Session, endpoint='session')
return app