From 698614075eefff6eebce000051dca67e3efb5337 Mon Sep 17 00:00:00 2001 From: michel-cf Date: Sun, 19 Jun 2016 19:59:08 +0200 Subject: [PATCH 1/5] OAuth service setup --- app/OAuth/__init__.py | 0 app/OAuth/controllers.py | 48 ++++++++++++++++++++++++++++++++++++++++ app/__init__.py | 2 ++ 3 files changed, 50 insertions(+) create mode 100644 app/OAuth/__init__.py create mode 100644 app/OAuth/controllers.py diff --git a/app/OAuth/__init__.py b/app/OAuth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/OAuth/controllers.py b/app/OAuth/controllers.py new file mode 100644 index 0000000..b1f9db4 --- /dev/null +++ b/app/OAuth/controllers.py @@ -0,0 +1,48 @@ +import datetime +import logging + +import Failures +from app import db, app + + +from flask_restful import Resource, Api +from flask import request, Blueprint + +from Validation import Validation + +from app.User import services as user_service +from app.User.models import ConfirmToken, ResetToken + +oauth_app = Blueprint('oauth', __name__, url_prefix='/oauth') +api = Api(oauth_app) + + +class ValidateUser(Resource): + + def post(self): + # Get values + server = request.headers.get('server') + email = request.form.get('email') + source = request.form.get('source') + + # Validate required fields + validation = Validation() + validation.add_required_field('server', server) + validation.add_required_field('email', email) + validation.add_required_field('source', source) + validation.check_email('email', email) + if not validation.is_valid(): + return validation.get_validation_response() + + # Validate user exits + user = user_service.get_user_by_email(email) + if user is None: + # New user + return Failures.unknown_user_email(email) + + logging.info('OAuth-controller: Validate: success: %s', user.id) + + return {'success': True} + + +api.add_resource(ValidateUser, '/validate') diff --git a/app/__init__.py b/app/__init__.py index 35815c3..0ca2971 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -119,12 +119,14 @@ from app.User.controllers import user_app from app.LocalUser.controllers import local_user_app from app.RateLimiting.controllers import rate_limiting_app +from app.OAuth.controllers import oauth_app app.register_blueprint(auth_token_app) app.register_blueprint(authenticate_app) app.register_blueprint(user_app) app.register_blueprint(local_user_app) app.register_blueprint(rate_limiting_app) +app.register_blueprint(oauth_app) # ------------------------------------------- Create DB -------------------------------------------------------- From b70469620bde3391f2933a06623d39a8544d7ff1 Mon Sep 17 00:00:00 2001 From: michel-cf Date: Sun, 19 Jun 2016 20:44:29 +0200 Subject: [PATCH 2/5] OAuth validate and create user. Add exception for wrong auth source --- Failures.py | 10 +++++++ app/Authenticate/controllers.py | 2 ++ app/OAuth/controllers.py | 46 ++++++++++++++++++++++++++++++++- app/User/services.py | 17 ++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Failures.py b/Failures.py index 5b20bfb..e96305f 100644 --- a/Failures.py +++ b/Failures.py @@ -114,3 +114,13 @@ def unknown_bucket_type(bucket_type): 'code': 180, 'data': bucket_type }, 500 + + +def wrong_auth_source(auth_source): + logging.debug('Failures: Wrong auth source: %s', auth_source) + return { + 'success': False, + 'message': 'Wrong auth source', + 'code': 480, + 'data': auth_source + }, 500 diff --git a/app/Authenticate/controllers.py b/app/Authenticate/controllers.py index d960145..bbc9263 100644 --- a/app/Authenticate/controllers.py +++ b/app/Authenticate/controllers.py @@ -46,6 +46,8 @@ def post(self): return Failures.email_not_confirmed() if user.blocked: return Failures.user_blocked() + if user.auth_source != 'local': + return Failures.wrong_auth_source(user.auth_source) if not rate_limiting_services.has_sufficient_tokens(user.id, 'failed-password', 1): return Failures.rate_exceeded() diff --git a/app/OAuth/controllers.py b/app/OAuth/controllers.py index b1f9db4..496b49a 100644 --- a/app/OAuth/controllers.py +++ b/app/OAuth/controllers.py @@ -37,12 +37,56 @@ def post(self): # Validate user exits user = user_service.get_user_by_email(email) if user is None: - # New user return Failures.unknown_user_email(email) + # Validate auth source + if user.auth_source != source: + return Failures.wrong_auth_source(user.auth_source) + logging.info('OAuth-controller: Validate: success: %s', user.id) return {'success': True} +class CreateUser(Resource): + + def post(self): + # Get values + server = request.headers.get('server') + email = request.form.get('email') + locale = request.form.get('locale') + screen_name = request.form.get('screenname') + source = request.form.get('source') + + # Validate required fields + validation = Validation() + validation.add_required_field('server', server) + validation.add_required_field('email', email) + validation.add_required_field('locale', locale) + validation.add_required_field('screenname', screen_name) + validation.add_required_field('source', source) + validation.check_email('email', email) + if not validation.is_valid(): + return validation.get_validation_response() + + # Validate email is not yet used + existing_user = user_service.get_user_by_email(email) + if existing_user is not None: + return Failures.email_already_in_use(email) + + # Validate screen name is not yet used + existing_user = user_service.get_user_by_screen_name(screen_name) + if existing_user is not None: + return Failures.screen_name_already_in_use(screen_name) + + id_user = user_service.create_oauth_user(server, email, source, locale, screen_name) + + db.session.commit() + + logging.info('OAuth-controller: create success: %s', id_user) + + # Create user + return {'success': True, 'user': id_user} + + api.add_resource(ValidateUser, '/validate') diff --git a/app/User/services.py b/app/User/services.py index b0d467b..1a71da8 100644 --- a/app/User/services.py +++ b/app/User/services.py @@ -58,6 +58,23 @@ def create_local_user(server, email, password, locale, screen_name): return user.id +def create_oauth_user(server, email, source, locale, screen_name): + # Save user + user = User() + user.email = email + user.locale = locale + user.screen_name = screen_name + user.auth_source = source + user.confirmed = True + user.blocked = False + + db.session.add(user) + db.session.flush() + db.session.refresh(user) + + return user.id + + def send_email_confirm(id_user, server): user = get_user(id_user) if user is None: From 5d4a0ffb8511260cca476b02c7ff5d35d6b25883 Mon Sep 17 00:00:00 2001 From: michel-cf Date: Sun, 19 Jun 2016 21:35:17 +0200 Subject: [PATCH 3/5] OAuth return user data and register create service --- app/OAuth/controllers.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/OAuth/controllers.py b/app/OAuth/controllers.py index 496b49a..0fb820e 100644 --- a/app/OAuth/controllers.py +++ b/app/OAuth/controllers.py @@ -45,7 +45,12 @@ def post(self): logging.info('OAuth-controller: Validate: success: %s', user.id) - return {'success': True} + return {'success': True, 'user': { + 'id': user.id, + 'email': user.email, + 'locale': user.locale, + 'screenname': user.screen_name + }} class CreateUser(Resource): @@ -90,3 +95,4 @@ def post(self): api.add_resource(ValidateUser, '/validate') +api.add_resource(CreateUser, '/create') From 0686269bbcee09e787cf0239205a9fab350f2763 Mon Sep 17 00:00:00 2001 From: michel-cf Date: Sat, 2 Jul 2016 19:13:46 +0200 Subject: [PATCH 4/5] Provide user with authentication source --- Failures.py | 10 ++++++++++ app/Authenticate/controllers.py | 3 ++- app/User/controllers.py | 32 ++++++++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Failures.py b/Failures.py index e96305f..d12ed9f 100644 --- a/Failures.py +++ b/Failures.py @@ -21,6 +21,16 @@ def unknown_user_email(email): }, 500 +def unknown_user_screen_name(screen_name): + logging.debug('Failures: Unknown user by screen name: %s', screen_name) + return { + 'success': False, + 'message': 'Unknown user screen name', + 'code': 400, + 'data': screen_name + }, 500 + + def email_already_in_use(email): logging.debug('Failures: Email already in use: %s', email) return { diff --git a/app/Authenticate/controllers.py b/app/Authenticate/controllers.py index bbc9263..836517d 100644 --- a/app/Authenticate/controllers.py +++ b/app/Authenticate/controllers.py @@ -65,7 +65,8 @@ def post(self): 'id': user.id, 'email': user.email, 'locale': user.locale, - 'screenname': user.screen_name + 'screenname': user.screen_name, + 'authentication-source': user.auth_source }} api.add_resource(AuthenticateLocalUser, '/local') diff --git a/app/User/controllers.py b/app/User/controllers.py index c549ffe..c4c8dbc 100644 --- a/app/User/controllers.py +++ b/app/User/controllers.py @@ -86,7 +86,8 @@ def get(self, id_user): 'id': user.id, 'email': user.email, 'locale': user.locale, - 'screenname': user.screen_name + 'screenname': user.screen_name, + 'authentication-source': user.auth_source }} @@ -104,7 +105,27 @@ def get(self, email): 'id': user.id, 'email': user.email, 'locale': user.locale, - 'screenname': user.screen_name + 'screenname': user.screen_name, + 'authentication-source': user.auth_source + }} + + +class GetUserByScreenname(Resource): + + def get(self, screen_name): + # Validate user exists, is validated and is not blocked + user = user_service.get_user_by_screen_name(screen_name) + if user is None: + return Failures.unknown_user_screen_name(screen_name) + + logging.info('User-controller: getUserByScreenname: success: %s (%s)', screen_name, user.screen_name) + + return {'success': True, 'user': { + 'id': user.id, + 'email': user.email, + 'locale': user.locale, + 'screenname': user.screen_name, + 'authentication-source': user.auth_source }} @@ -144,7 +165,8 @@ def post(self, id_user): 'id': user.id, 'email': user.email, 'locale': user.locale, - 'screenname': user.screen_name + 'screenname': user.screen_name, + 'authentication-source': user.auth_source }} @@ -179,12 +201,14 @@ def post(self, id_user): 'id': user.id, 'email': user.email, 'locale': user.locale, - 'screenname': user.screen_name + 'screenname': user.screen_name, + 'authentication-source': user.auth_source }} api.add_resource(Register, '/register') api.add_resource(GetUserById, '/id/') api.add_resource(GetUserByEmail, '/email/') +api.add_resource(GetUserByScreenname, '/screenname/') api.add_resource(DoInfoChange, '/info/') api.add_resource(DoLocaleChange, '/locale/') From 88fbb71b9a885defde3f6cd6cb8432ab60b067c9 Mon Sep 17 00:00:00 2001 From: michel-cf Date: Sun, 3 Jul 2016 00:12:31 +0200 Subject: [PATCH 5/5] Check authentication source for local user only services --- app/LocalUser/controllers.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/LocalUser/controllers.py b/app/LocalUser/controllers.py index 01dee3b..ba0a45e 100644 --- a/app/LocalUser/controllers.py +++ b/app/LocalUser/controllers.py @@ -37,6 +37,9 @@ def post(self): if user is None: return Failures.unknown_user_email(email) + if user.auth_source != 'local': + return Failures.wrong_auth_source(user.auth_source) + # Delete expired tokens ConfirmToken.query.filter(ConfirmToken.validity < datetime.datetime.now()).delete() db.session.flush() @@ -78,6 +81,9 @@ def get(self, email): if user is None: return Failures.unknown_user_email(email) + if user.auth_source != 'local': + return Failures.wrong_auth_source(user.auth_source) + success, code, message = user_service.send_email_confirm(user.id, server) db.session.commit() @@ -119,6 +125,9 @@ def post(self, email): if user is None: return Failures.unknown_user_email(email) + if user.auth_source != 'local': + return Failures.wrong_auth_source(user.auth_source) + # Validate password strength and confirm if password != password_confirm: return Failures.passwords_do_not_match() @@ -165,6 +174,9 @@ def get(self, email): if user is None: return Failures.unknown_user_email(email) + if user.auth_source != 'local': + return Failures.wrong_auth_source(user.auth_source) + success, code, message = user_service.send_password_reset(user.id, server) db.session.commit() @@ -204,6 +216,9 @@ def post(self, id_user): if user is None: return Failures.unknown_user_id(id_user) + if user.auth_source != 'local': + return Failures.wrong_auth_source(user.auth_source) + # Validate password strength and confirm if password != password_confirm: return Failures.passwords_do_not_match()