From 777d05c26cb113ad952079a43447a39e30adefab Mon Sep 17 00:00:00 2001 From: alpcentaur Date: Wed, 25 Oct 2023 09:47:56 +0000 Subject: [PATCH] basic oauth added --- .gitignore | 2 +- input/asgi.py | 16 ++++ input/middleware/__init__.py | 0 input/middleware/oauth.py | 84 +++++++++++++++++++ input/settings.py | 30 +++++++ input/settings.py.old | 41 +++++++++ .../input/if_end_of_project_approved.html | 2 +- .../input/if_end_of_project_approved.txt | 2 +- requirements.txt | 14 ++++ 9 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 input/asgi.py create mode 100644 input/middleware/__init__.py create mode 100644 input/middleware/oauth.py create mode 100755 input/settings.py.old diff --git a/.gitignore b/.gitignore index f041b72..f796096 100755 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ /staticfiles # /foerderbarometer/settings.py /foerderbarometer/*settings* -/foerderbarometer/input/settings.py +/input/settings.py /nohup.out /logfile *~ diff --git a/input/asgi.py b/input/asgi.py new file mode 100644 index 0000000..2ff9254 --- /dev/null +++ b/input/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for oauth_demo project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oauth_demo.settings') + +application = get_asgi_application() diff --git a/input/middleware/__init__.py b/input/middleware/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/input/middleware/oauth.py b/input/middleware/oauth.py new file mode 100644 index 0000000..ca30b1f --- /dev/null +++ b/input/middleware/oauth.py @@ -0,0 +1,84 @@ +from authlib.integrations.base_client import OAuthError +from authlib.integrations.django_client import OAuth +from authlib.oauth2.rfc6749 import OAuth2Token +from django.shortcuts import redirect +from django.utils.deprecation import MiddlewareMixin +from foerderbarometer import settings +from input import views + + +class OAuthMiddleware(MiddlewareMixin): + + def __init__(self, get_response=None): + super().__init__(get_response) + self.oauth = OAuth() + + def process_request(self, request): + if settings.OAUTH_URL_WHITELISTS is not None: + for w in settings.OAUTH_URL_WHITELISTS: + if request.path.startswith(w): + return self.get_response(request) + + def update_token(token, refresh_token, access_token): + request.session['token'] = token + print('oioi') + print('oi token', token) + return None + + sso_client = self.oauth.register( + settings.OAUTH_CLIENT_NAME, overwrite=True, **settings.OAUTH_CLIENT, update_token=update_token + ) + + if request.path.startswith('/oauth/callback'): + print('oi') + self.clear_session(request) + request.session['token'] = sso_client.authorize_access_token(request) + print('blub', request.session['token']) + print('user', self.get_current_user(sso_client, request)) + if self.get_current_user(sso_client, request) is not None: + redirect_uri = request.session.pop('redirect_uri', None) + if redirect_uri is not None: + return redirect(redirect_uri) + return redirect(views.ExternView) + + if request.session.get('token', None) is not None: + current_user = self.get_current_user(sso_client, request) + if current_user is not None: + return self.get_response(request) + + # remember redirect URI for redirecting to the original URL. + request.session['redirect_uri'] = request.path + return sso_client.authorize_redirect(request, settings.OAUTH_CLIENT['redirect_uri']) + + # fetch current login user info + # 1. check if it's in cache + # 2. fetch from remote API when it's not in cache + @staticmethod + def get_current_user(sso_client, request): + token = request.session.get('token', None) + if token is None or 'access_token' not in token: + return None + + if not OAuth2Token.from_dict(token).is_expired() and 'user' in request.session: + return request.session['user'] + + try: + res = sso_client.get(settings.OAUTH_CLIENT['userinfo_endpoint'], token=OAuth2Token(token)) + print('json oi oi' , res.json()) + if res.ok: + request.session['user'] = res.json() + return res.json() + except OAuthError as e: + print(e) + return None + + @staticmethod + def clear_session(request): + try: + del request.session['user'] + del request.session['token'] + except KeyError: + pass + + def __del__(self): + print('destroyed') diff --git a/input/settings.py b/input/settings.py index 3b43e9a..6d9bf53 100755 --- a/input/settings.py +++ b/input/settings.py @@ -39,3 +39,33 @@ ACCOUNTS ={ # "21103": '21103 Willkommen', "21140": '21140 Wikipedia-Kampagne', "21141": '21141 Wikipedia-Onboarding', "21150": '21150 Fürsorge und Online-Kommunikationskultur',} + + + +# teken from working oauth prototype as additional settings + +WSGI_APPLICATION = 'oauth_demo.wsgi.application' + +# OAuth Settings +OAUTH_URL_WHITELISTS = [] + +OAUTH_CLIENT_NAME = '' + + + +OAUTH_CLIENT = { + 'client_id': '', + 'client_secret': '', + 'access_token_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/access_token', + 'authorize_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/authorize', + 'api_base_url': 'https://meta.wikimedia.org/w/rest.php/oauth2/resource', + 'redirect_uri': 'http://localhost:8000/oauth/callback', + 'client_kwargs': { + 'scope': 'basic', + 'token_placement': 'header' + }, + 'userinfo_endpoint': 'resource/profile', +} + +OAUTH_COOKIE_SESSION_ID = 'sso_session_id' + diff --git a/input/settings.py.old b/input/settings.py.old new file mode 100755 index 0000000..3b43e9a --- /dev/null +++ b/input/settings.py.old @@ -0,0 +1,41 @@ +# mail for IF-OTRS +IF_EMAIL = 'community@wikimedia.de' +#IF_EMAIL = 'test-luca-ext@wikimedia.de' +#SURVEY_EMAIL = 'christof.pins@wikimedia.de' +#SURVEY_EMAIL = 'luca.wulf@cannabinieri.de' +SURVEY_EMAIL = 'sandro.halank@wikimedia.de' +# prefix for urls +SURVEYPREFIX = 'https://wikimedia.sslsurvey.de/Foerderbarometer/?' + +# some links +DATAPROTECTION = "https://www.wikimedia.de/datenschutz/#datenerfassung" +FOERDERRICHTLINIEN = "https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/F%C3%B6rderrichtlinien" +NUTZUNGSBEDINGUNGEN = 'static/input/nutzungsbedingungen.html' + +LANGUAGE_CODE = 'de' +TIME_ZONE = 'UTC' +USE_I18N = True +USE_L10N = True +USE_TZ = True + + +ACCOUNTS ={ # "21103": '21103 Willkommen', + "DEF": 'DEFAULT VALUE, you hould not see this!', + "21111": '21111 Förderung (reaktiv)', + "21112": '21112 WikiCon', +# "21113": '21113 Wikimania/Unterstützung Ehrenamtliche', + "21115": '21115 Lokale Räume, Berlin', + "21116": '21116 Lokale Räume, Hamburg', + "21117": '21117 Lokale Räume, Hannover', + "21118": '21118 Lokale Räume, Köln', + "21119": '21119 Lokale Räume, München', + "21120": '21120 Lokale Räume, Fürth', + "21125": '21125 Lokale Räume, allgemein', + "21130": '21130 GLAM-Förderung', + "21131": '21131 Initiative Förderung', +# "21134": '21134 Größe', +# "21137": '21137 Beitragen', +# "21138": '21138 Vermittlung', + "21140": '21140 Wikipedia-Kampagne', + "21141": '21141 Wikipedia-Onboarding', + "21150": '21150 Fürsorge und Online-Kommunikationskultur',} diff --git a/input/templates/input/if_end_of_project_approved.html b/input/templates/input/if_end_of_project_approved.html index 75a5893..7e442ff 100755 --- a/input/templates/input/if_end_of_project_approved.html +++ b/input/templates/input/if_end_of_project_approved.html @@ -10,7 +10,7 @@ Da wir verpflichtet sind, über unsere geförderten Maßnahmen zu berichten, mö * Wie viele Personen haben an dem Projekt teilgenommen?
* Wo können die Ergebnisse des Projektes eingesehen werden? (Projektseite, Commons-Link, Bericht o. ä.)

-Sollten bei dem Projekt Fotos oder andere Mediendateien entstanden sein, findest du hier eine Anleitung, wie diese bei Commons hochgeladen werden sollen. +Sollten bei dem Projekt Fotos oder andere Mediendateien entstanden sein, findest du hier eine Anleitung, wie diese bei Commons hochgeladen werden sollen.

Solltest du einen öffentlichen Förderantrag in der Wikipedia erstellt haben, kannst du diesen nun archivieren, indem du den Projektstatus oben im Quellcode entsprechend anpasst und die Liste der geförderten Aktivitäten entsprechend aktualisierst.

diff --git a/input/templates/input/if_end_of_project_approved.txt b/input/templates/input/if_end_of_project_approved.txt index 6d7f941..6ca687b 100755 --- a/input/templates/input/if_end_of_project_approved.txt +++ b/input/templates/input/if_end_of_project_approved.txt @@ -8,7 +8,7 @@ Da wir verpflichtet sind, über unsere geförderten Maßnahmen zu berichten, mö * Wie viele Personen haben an dem Projekt teilgenommen? * Wo können die Ergebnisse des Projektes eingesehen werden? (Projektseite, Commons-Link, Bericht o. ä.) -Sollten bei dem Projekt Fotos oder andere Mediendateien entstanden sein, findest du hier eine Anleitung, wie diese bei Commons hochgeladen werden sollen. +Sollten bei dem Projekt Fotos oder andere Mediendateien entstanden sein, findest du hier eine Anleitung, wie diese bei Commons hochgeladen werden sollen: https://commons.wikimedia.org/wiki/Category:Supported_by_Wikimedia_Deutschland Solltest du einen öffentlichen Förderantrag in der Wikipedia erstellt haben, kannst du diesen nun archivieren, indem du den Projektstatus oben im Quellcode entsprechend anpasst und die Liste der geförderten Aktivitäten entsprechend aktualisierst. diff --git a/requirements.txt b/requirements.txt index 59966ae..1c54076 100755 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,17 @@ gunicorn==20.0.4 mysqlclient==2.1.1 sqlparse==0.4.3 whitenoise==6.2.0 +asgiref +Authlib==1.2.1 +certifi==2023.7.22 +cffi==1.16.0 +chardet==5.2.0 +charset-normalizer==3.3.0 +cryptography==41.0.4 +idna==3.4 +pycparser==2.21 +pytz==2023.3.post1 +requests==2.31.0 +six==1.16.0 +typing_extensions==4.8.0 +urllib3==2.0.6