diff --git a/Pipfile b/Pipfile index d1a67df51cdde9c86c390ea0b8a8228a527f87f8..b267e798ae199dd87a2bc82ceaa9ba415f846060 100644 --- a/Pipfile +++ b/Pipfile @@ -16,6 +16,8 @@ flask-jwt-extended = "*" marshmallow-enum = "*" storage = { git="git@gitlab.fi.muni.cz:grp-kontr2/kontr-storage-module.git", editable='true' } gitpython = "*" +flask-oauthlib = "*" +pyopenssl = "*" [dev-packages] @@ -24,4 +26,4 @@ gitpython = "*" [requires] -python_version = "3.6" \ No newline at end of file +python_version = "3.6" diff --git a/portal/__init__.py b/portal/__init__.py index c1b11443a2d76a2948c83d2aee0da1f6daa4bca3..64509713c461c971378864de439af514e2996510 100644 --- a/portal/__init__.py +++ b/portal/__init__.py @@ -1,5 +1,6 @@ from flask import Flask from flask_jwt_extended import JWTManager +from flask_oauthlib.client import OAuth from portal.config import CONFIGURATIONS from flask_sqlalchemy import SQLAlchemy @@ -9,6 +10,7 @@ from storage import Storage db = SQLAlchemy() jwt = JWTManager() +oauth = OAuth() # TODO - urgent storage = Storage({ "submissions_dir": "todo", @@ -22,7 +24,7 @@ def config_app(flask_app): config_type = os.environ.get('PORTAL_CONFIG_TYPE', 'devel') config_object = CONFIGURATIONS[config_type] if config_object is None: - raise EnvironmentError() # TODO some custom ex + raise RuntimeError() flask_app.config.from_object(config_object) # app.logger.removeHandler(default_handler) # from Flask release 1.0, not yet available @@ -35,6 +37,9 @@ def create_app(): db.init_app(app) # init the jwt jwt.init_app(app) + # init the oauth client + oauth.init_app(app) return app + import portal.database.models diff --git a/portal/rest/auth/gitlab.py b/portal/rest/auth/gitlab.py new file mode 100644 index 0000000000000000000000000000000000000000..78be942fc2654745ee1658c3d7d29db4b2da5c6a --- /dev/null +++ b/portal/rest/auth/gitlab.py @@ -0,0 +1,64 @@ +from flask import Blueprint, Flask, Config, url_for, request, redirect, session, jsonify, \ + make_response +from flask_oauthlib.client import OAuth, OAuthRemoteApp + +from portal import oauth + + +def extract_user_info(me: dict): + return dict( + uco=None, # TODO: Need from gitlab or prompt the user + name=me['name'], + username=me['username'], + email=me['email'] + ) + + +def create_gitlab_app(oauth: OAuth) -> OAuthRemoteApp: + base_url = "https://gitlab.fi.muni.cz" + client_id = "323ee2a6e24291f899b8415bf6af2a0e89beed711de8a59e01a1291daecea330" + client_secret = "323ee2a6e24291f899b8415bf6af2a0e89beed711de8a59e01a1291daecea330" + + return oauth.remote_app( + 'gitlab', + base_url=base_url, + request_token_url=None, + access_token_url=base_url + "/oauth/token", + authorize_url=base_url + "/oauth/authorize", + access_token_method='POST', + consumer_key=client_id, + consumer_secret=client_secret + ) + + +gitlab = create_gitlab_app(oauth=oauth) +oauth = Blueprint('oauth', __name__, url_prefix='/oauth') + + +@oauth.route('/login', methods=['GET']) +def oauth_login(): + callback = url_for('oauth.oauth_authorized', _external=True, _scheme='https') + return gitlab.authorize(callback=callback) + + +@oauth.route('/login/authorized', methods=['GET']) +def oauth_authorized(): + resp = gitlab.authorized_response() + if resp is None: + return 'Access denied: reason=%s error=%s' % ( + request.args['error'], + request.args['error_description'] + ) + + token = resp['access_token'] + session['gitlab_token'] = (token, '') + me = gitlab.get('/api/v4/user') + user_info = extract_user_info(me) + data = dict(data=me.data, token=token) + return jsonify(data) + + +@gitlab.tokengetter +def get_gitlab_oauth_token(): + token = session.get('gitlab_token') + return token diff --git a/portal/service/errors.py b/portal/service/errors.py index 72a4a3084ba95e62cd0c11e8463afdef41d17179..c2e4ee1a075f9b6754959a8acc194eeaa278ed90 100644 --- a/portal/service/errors.py +++ b/portal/service/errors.py @@ -6,6 +6,10 @@ class PortalError(RuntimeError): """ +class PortalConfigurationLoadError(PortalError): + pass + + class PortalAPIError(Exception): def __init__(self, code, message): self._code = code diff --git a/run.py b/run.py index e2ef812353912d5305577077ccf43dbfb1d27c76..be86174135155e0f3ce083fc7b846f8a5c11f500 100644 --- a/run.py +++ b/run.py @@ -1,5 +1,6 @@ from portal import create_app from portal import db +from portal.rest.auth.gitlab import oauth from portal.rest.auth.login import auth from sample_data.data_init import init_data @@ -7,6 +8,8 @@ from portal.rest.courses.courses import courses from portal.rest.users.users import users from portal.rest.roles.roles import roles from portal.rest.groups.groups import groups +from portal.rest.submissions.submissions import submissions +from portal.rest.projects.projects import projects def init_db(app): @@ -22,7 +25,10 @@ if __name__ == '__main__': app.register_blueprint(users) app.register_blueprint(roles) app.register_blueprint(groups) + app.register_blueprint(submissions) + app.register_blueprint(projects) app.register_blueprint(auth) + app.register_blueprint(oauth) # app.run(use_reloader=False) app.run()