Browse Source

full example with one little change in code to make it work, some changes in the settings file

master
alpcentaur 11 months ago
commit
1352d58e03
27 changed files with 385 additions and 0 deletions
  1. +4
    -0
      .gitignore
  2. +21
    -0
      LICENSE
  3. +33
    -0
      README.md
  4. +21
    -0
      manage.py
  5. +0
    -0
      oauth_demo/__init__.py
  6. BIN
      oauth_demo/__pycache__/__init__.cpython-37.pyc
  7. BIN
      oauth_demo/__pycache__/__init__.cpython-39.pyc
  8. BIN
      oauth_demo/__pycache__/settings.cpython-37.pyc
  9. BIN
      oauth_demo/__pycache__/settings.cpython-39.pyc
  10. BIN
      oauth_demo/__pycache__/urls.cpython-37.pyc
  11. BIN
      oauth_demo/__pycache__/urls.cpython-39.pyc
  12. BIN
      oauth_demo/__pycache__/views.cpython-37.pyc
  13. BIN
      oauth_demo/__pycache__/views.cpython-39.pyc
  14. BIN
      oauth_demo/__pycache__/wsgi.cpython-37.pyc
  15. BIN
      oauth_demo/__pycache__/wsgi.cpython-39.pyc
  16. +16
    -0
      oauth_demo/asgi.py
  17. +0
    -0
      oauth_demo/middleware/__init__.py
  18. BIN
      oauth_demo/middleware/__pycache__/__init__.cpython-37.pyc
  19. BIN
      oauth_demo/middleware/__pycache__/__init__.cpython-39.pyc
  20. BIN
      oauth_demo/middleware/__pycache__/oauth.cpython-37.pyc
  21. BIN
      oauth_demo/middleware/__pycache__/oauth.cpython-39.pyc
  22. +84
    -0
      oauth_demo/middleware/oauth.py
  23. +145
    -0
      oauth_demo/settings.py
  24. +23
    -0
      oauth_demo/urls.py
  25. +6
    -0
      oauth_demo/views.py
  26. +16
    -0
      oauth_demo/wsgi.py
  27. +16
    -0
      requirements.txt

+ 4
- 0
.gitignore View File

@ -0,0 +1,4 @@
.idea/
db.sqlite3
venv2/

+ 21
- 0
LICENSE View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Songrong Jiang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 33
- 0
README.md View File

@ -0,0 +1,33 @@
# Wikimedia OAuth2 Django Demo
A minimal prototype showing how to authenticate wikimedia
users with OAuth2
## Quick Start
1. Create virtual environment
```bash
virtualenv --python=python3.9 venv
```
1. Install requirements
```bash
pip install -r requirements.txt
```
1. Run the server
```bash
python manage.py migrate
python manage.py runserver
```
## Behind the scene
The OAuth2 configuration is located at settings.py
The default session backend is sqlite3.
The base for this prototype was done by songrgg, who published
his code on Microsoft's Github. His Blog Post you can find here:
https://songrgg.github.io/programming/django-oauth-client-setup

+ 21
- 0
manage.py View File

@ -0,0 +1,21 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oauth_demo.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

+ 0
- 0
oauth_demo/__init__.py View File


BIN
oauth_demo/__pycache__/__init__.cpython-37.pyc View File


BIN
oauth_demo/__pycache__/__init__.cpython-39.pyc View File


BIN
oauth_demo/__pycache__/settings.cpython-37.pyc View File


BIN
oauth_demo/__pycache__/settings.cpython-39.pyc View File


BIN
oauth_demo/__pycache__/urls.cpython-37.pyc View File


BIN
oauth_demo/__pycache__/urls.cpython-39.pyc View File


BIN
oauth_demo/__pycache__/views.cpython-37.pyc View File


BIN
oauth_demo/__pycache__/views.cpython-39.pyc View File


BIN
oauth_demo/__pycache__/wsgi.cpython-37.pyc View File


BIN
oauth_demo/__pycache__/wsgi.cpython-39.pyc View File


+ 16
- 0
oauth_demo/asgi.py View File

@ -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()

+ 0
- 0
oauth_demo/middleware/__init__.py View File


BIN
oauth_demo/middleware/__pycache__/__init__.cpython-37.pyc View File


BIN
oauth_demo/middleware/__pycache__/__init__.cpython-39.pyc View File


BIN
oauth_demo/middleware/__pycache__/oauth.cpython-37.pyc View File


BIN
oauth_demo/middleware/__pycache__/oauth.cpython-39.pyc View File


+ 84
- 0
oauth_demo/middleware/oauth.py View File

@ -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 oauth_demo import settings
from oauth_demo 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.index)
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')

+ 145
- 0
oauth_demo/settings.py View File

@ -0,0 +1,145 @@
"""
Django settings for oauth_demo project.
Generated by 'django-admin startproject' using Django 3.0.5.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '#jk+74g_ilb4h)f!_20mmcg^5-+veuj2(v%0ufymq+r%mc3im-'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'oauth_demo.middleware.oauth.OAuthMiddleware'
]
ROOT_URLCONF = 'oauth_demo.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'oauth_demo.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
# OAuth Settings
OAUTH_URL_WHITELISTS = []
OAUTH_CLIENT_NAME = '<name-of-the-configured-wikimedia-app>'
OAUTH_CLIENT = {
'client_id': '<client-application-key-of-wikimedia-app>',
'client_secret': '<client-application-secret-of-wikimedia-app>',
'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'

+ 23
- 0
oauth_demo/urls.py View File

@ -0,0 +1,23 @@
"""oauth_demo URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from oauth_demo.views import index
urlpatterns = [
path('', index),
path('admin/', admin.site.urls),
]

+ 6
- 0
oauth_demo/views.py View File

@ -0,0 +1,6 @@
from django.http import HttpResponse
def index(request):
msg = "Hello %s, you're logined." % request.session['user']['username']
return HttpResponse(msg)

+ 16
- 0
oauth_demo/wsgi.py View File

@ -0,0 +1,16 @@
"""
WSGI config for oauth_demo project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oauth_demo.settings')
application = get_wsgi_application()

+ 16
- 0
requirements.txt View File

@ -0,0 +1,16 @@
asgiref==3.7.2
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
Django==4.2.6
idna==3.4
pycparser==2.21
pytz==2023.3.post1
requests==2.31.0
six==1.16.0
sqlparse==0.4.4
typing_extensions==4.8.0
urllib3==2.0.6

Loading…
Cancel
Save