diff options
author | Ivan Dolgov <ivan@dolgov.fi> | 2018-06-29 16:27:18 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2018-07-12 11:13:13 +0300 |
commit | 33b21c676584f7a1cf584b0aeb0127e45ca0d443 (patch) | |
tree | 70c6fdf5ea17a42dabd37238715bf1c19c8c425b | |
parent | 5e68c02a915ff50a9b8bc14b7f68c255be92cf21 (diff) | |
download | qvisqve-33b21c676584f7a1cf584b0aeb0127e45ca0d443.tar.gz |
Add: trivial user login flow
-rw-r--r-- | qvisqve/__init__.py | 3 | ||||
-rw-r--r-- | qvisqve/api.py | 2 | ||||
-rw-r--r-- | qvisqve/auth_router.py | 51 | ||||
-rw-r--r-- | qvisqve/login_router.py | 39 | ||||
-rw-r--r-- | qvisqve/responses.py | 9 | ||||
-rw-r--r-- | qvisqve/token_router.py | 27 | ||||
-rw-r--r-- | views/login.tpl | 18 |
7 files changed, 144 insertions, 5 deletions
diff --git a/qvisqve/__init__.py b/qvisqve/__init__.py index a1d80f9..32032b6 100644 --- a/qvisqve/__init__.py +++ b/qvisqve/__init__.py @@ -19,12 +19,15 @@ from .responses import ( created_response, ok_response, unauthorized_response, + found_response, ) from .log_setup import setup_logging, log from .token import TokenGenerator from .router import Router from .version_router import VersionRouter +from .login_router import LoginRouter +from .auth_router import AuthRouter from .token_router import TokenRouter from .api import API diff --git a/qvisqve/api.py b/qvisqve/api.py index 2dee954..a6d71ef 100644 --- a/qvisqve/api.py +++ b/qvisqve/api.py @@ -27,6 +27,8 @@ class API: routers = [ qvisqve.VersionRouter(), + qvisqve.LoginRouter(), + qvisqve.AuthRouter(self._config.get('callback_url', 'localhost')), qvisqve.TokenRouter( self._create_token_generator(), self._get_clients()), ] diff --git a/qvisqve/auth_router.py b/qvisqve/auth_router.py new file mode 100644 index 0000000..d4f3ca6 --- /dev/null +++ b/qvisqve/auth_router.py @@ -0,0 +1,51 @@ +# Copyright (C) 2018 Ivan Dolgov +# +# 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/>. + + +import urllib.parse + + +import qvisqve + + +class AuthRouter(qvisqve.Router): + + def __init__(self, callback_url): + super().__init__() + self._callback_url = callback_url + + def get_routes(self): + return [ + { + 'method': 'POST', + 'path': '/auth', + 'callback': self._auth, + 'needs-authorization': False, + }, + ] + + def _auth(self, content_type, body, *args, **kwargs): + if content_type != 'application/x-www-form-urlencoded': + return qvisqve.bad_request_response('Wrong content type') + + # TODO: + # - perform actual auth + # - create and store auth code + # - use callback url provided in request + + params = urllib.parse.urlencode({'code': 123}) + url = '{}?{}'.format(self._callback_url, params) + + return qvisqve.found_response('Redirect to callback url', url) diff --git a/qvisqve/login_router.py b/qvisqve/login_router.py new file mode 100644 index 0000000..275f175 --- /dev/null +++ b/qvisqve/login_router.py @@ -0,0 +1,39 @@ +# Copyright (C) 2018 Ivan Dolgov +# +# 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/>. + + +import bottle + + +import qvisqve + + +class LoginRouter(qvisqve.Router): + + def get_routes(self): + return [ + { + 'method': 'GET', + 'path': '/login', + 'callback': self._login, + 'needs-authorization': False, + }, + ] + + def _login(self, *args, **kwargs): + headers = { + 'Content-Type': 'text/html; charset=utf-8', + } + return qvisqve.ok_response(bottle.template('login'), headers=headers) diff --git a/qvisqve/responses.py b/qvisqve/responses.py index 281ec43..d36094e 100644 --- a/qvisqve/responses.py +++ b/qvisqve/responses.py @@ -57,3 +57,12 @@ def unauthorized_response(body): 'Content-Type': 'text/plain', } return response(apifw.HTTP_UNAUTHORIZED, body, headers) + + +def found_response(body, location): + headers = { + 'Content-Type': 'text/plain', + 'Location': location, + } + # TODO: use apifw.FOUND_CREATED when available + return response(302, body, headers) diff --git a/qvisqve/token_router.py b/qvisqve/token_router.py index 9acc924..f87037e 100644 --- a/qvisqve/token_router.py +++ b/qvisqve/token_router.py @@ -47,14 +47,25 @@ class TokenRouter(qvisqve.Router): if content_type != 'application/x-www-form-urlencoded': return qvisqve.bad_request_response('Wrong content type') - client_id, client_secret = bottle.request.auth - if not self._clients.is_correct_secret(client_id, client_secret): - return qvisqve.unauthorized_response('Unauthorized') - params = self._get_form_params(body) grant_type = self._get_grant_type(params) - if grant_type != 'client_credentials': + if grant_type == 'client_credentials': + client_id, client_secret = bottle.request.auth + if not self._clients.is_correct_secret(client_id, client_secret): + return qvisqve.unauthorized_response('Unauthorized') + elif grant_type == 'authorization_code': + code = self._get_code(params) + # FIXME + if code is None or code != '123': + return qvisqve.unauthorized_response('Unauthorized') + empty_token = self._generator.new_token('', '') + return qvisqve.ok_response({ + 'access_token': empty_token, + 'token_type': 'bearer', + 'scope': '', + }) + else: return qvisqve.bad_request_response('Wrong grant type') scope = self._get_scope(params) @@ -85,6 +96,12 @@ class TokenRouter(qvisqve.Router): return grant_type[0] return None + def _get_code(self, params): + code = params.get('code') + if len(code) == 1: + return code[0] + return None + def _get_scope(self, params): scope = params.get('scope', []) if len(scope) > 1: diff --git a/views/login.tpl b/views/login.tpl new file mode 100644 index 0000000..dae2c4c --- /dev/null +++ b/views/login.tpl @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta name="description" content="Qvisqve Login"> + <meta name="author" content="Qvarnlabs Ltd"> + <title>Qvisqve Login</title> + </head> + <body> + <form action="/auth" method="POST"> + User name: <input name="username" type="text" /> + <br /> + Password: <input name="password" type="password" /> + <br /> + <input type="submit" value="Login" /> + </form> + </body> +</html> |