Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Review] Quite a lot of minor improvements #1

Open
wants to merge 72 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
7ddc980
Fix python2 import back
Jul 12, 2016
dcc8b07
Avoid bytes usage for python 2.7
Jul 12, 2016
4f09d92
Avoid annoying deprecation warnings for django 1.10
Jul 12, 2016
37ad2bb
Get logout url from provider_info dict; pep8
Jul 12, 2016
4374b48
Make raw id_token available for Client class
Jul 12, 2016
6b4553a
Disable fail on unavailable backend on application init; pep8
Jul 12, 2016
a399a40
fix exception when session[next] not defined
Jul 22, 2016
85747e6
Gently redirect user to LOGOUT_REDIRECT_URL if it's defined, preventi…
Jul 26, 2016
5cab86a
Correctly handle client.callback error if it's returned, not raised
Aug 8, 2016
0dbc898
Add tests and tox runner; comment outdated Azure IDP configuration
Aug 8, 2016
bdc16cb
accept OP urls both with slash and without slash
Sep 8, 2016
68842b9
urls with optional slash at the end
Sep 9, 2016
b7b2ad2
assume requestcontext is used by default for django 1.10
Sep 11, 2016
f93a653
Logout even if user was logged in not with OIDC
Sep 13, 2016
bc11cbc
Support for acr_value parameter
Sep 22, 2016
9d576b8
Allow normal auth flow even if userinfo endpoint ommited or not imple…
Sep 23, 2016
fe226cf
Raise readable error if response is missing or faulty
Sep 23, 2016
5237ad8
Better error handling for authz_cb view
Oct 16, 2016
33bce98
Raise exception when someone tries to create dynamic client when it's…
Nov 24, 2016
4d0fd15
Fix py3 compat
thomasf Jan 24, 2017
b2f1011
Modify package publishing meta data
thomasf Jan 24, 2017
ef63d55
Require django 1.10 or newer
thomasf Jan 24, 2017
79a445f
Only care about python 3 support
thomasf Jan 24, 2017
ae304ba
Update readme with additions for fork
thomasf Jan 24, 2017
8623375
Set version to 0.0.1
thomasf Jan 24, 2017
0b3d46d
Add isort config
thomasf Feb 15, 2017
81b1614
Sort imports
thomasf Feb 15, 2017
33ba4d9
Remove everything older than py3.5 dj1.1 from tox env list
thomasf Feb 15, 2017
1083673
Remove requirements file
thomasf Feb 15, 2017
e57f590
Formatted with autopep8
thomasf Feb 15, 2017
94480aa
Remove py2 code
thomasf Feb 15, 2017
c677497
Move view error handlers to one function
thomasf Feb 15, 2017
fdf715b
Version 0.0.2
thomasf Feb 15, 2017
0dab78b
Add pypi package install to readme
thomasf Feb 17, 2017
5d62003
merge
Apr 30, 2017
cb93692
Fix Unicode usage for python2/3
May 1, 2017
6a0d1c7
Fix daphne compat
thomasf May 5, 2017
ca3491d
Bump oic dependency version
thomasf May 5, 2017
5f1b033
Version 0.0.3
thomasf May 5, 2017
3dd894d
Add py36 and dj111 to tox env
thomasf May 11, 2017
51d8b09
Disallow unnamed kwd args
thomasf May 11, 2017
c3079f5
Added request to the authenticate method
Jul 29, 2016
413355e
Remove unnecessary import
thomasf May 11, 2017
53a054c
Force extra_args to be explicit keyword arg
thomasf May 11, 2017
496fad0
Version 0.0.4
thomasf May 11, 2017
66c54c1
Send kwargs to configure_user function
thomasf May 14, 2017
c3a8dd1
Version 0.0.5
thomasf May 14, 2017
beeca78
Return http status 404 when dynamic clients are disabled
thomasf May 16, 2017
a5d68f3
Quick fix for e500 when login view is called with bad session state
thomasf May 16, 2017
1bf2287
Simplify tox.ini
thomasf May 16, 2017
ae1bd79
WIP drone
thomasf May 16, 2017
e6de2e0
Version 0.0.6
thomasf May 16, 2017
e48e1d5
Update drone config
thomasf May 16, 2017
f8c2860
Add **kwargs to default backend impl
thomasf Jun 25, 2017
05e54dc
Add specific authentication failed exception
thomasf Jun 26, 2017
7932d0e
Bump version
thomasf Jun 26, 2017
fa8c30a
Add auth token expires_in into django session
thomasf Aug 30, 2017
57323b3
Merge pull request #5 from py-pa/expose_token_expires_in_in_session
thomasf Aug 30, 2017
530264d
v0.0.8
thomasf Aug 30, 2017
c94d037
Merge with py-pa/django-oidc
Sep 9, 2017
527cfbc
Visually fix py2.7 compatibility
Sep 9, 2017
fce378a
Use less ugly unicode compat approach
Sep 9, 2017
b9e9646
Merge pull request #1 from koriaf/test_merge
Sep 9, 2017
3b7aa3e
Update README.rst
Sep 9, 2017
48b7b75
Fix naive datetime to timezone-aware for default backend
Sep 10, 2017
82630cd
Added a check for "keyset_jwk_file" in setting up clients in OIDCClie…
srmoore Oct 4, 2017
1930d37
Added in looking for a keyset_jwk_file in the 'client_registration' s…
srmoore Oct 4, 2017
acdcbe6
Updated README.rs to include how to specify a client with private_key…
srmoore Oct 5, 2017
53f4350
Merge pull request #2 from srmoore/master
Oct 6, 2017
2427f75
Django 2.2 support
timothy-spencer Oct 12, 2019
3c99327
Replaced render_to_response with render
reggieriser Jan 27, 2020
ae4a0ba
More Django 3.0 changes
reggieriser Jan 27, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
pipeline:
restore-cache:
image: drillster/drone-volume-cache
restore: true
mount:
- cache
- .tox
volumes:
- /tmp/drone-cache:/cache

build:
image: python:3.5
commands:
- mkdir -p cache/pip
- pip -q install --upgrade --cache-dir cache/pip tox flake8
- tox -e py35-django110
# - flake8 --config=.flake8rc
# - "isort -df -c -rc"

dist:
image: python:3.5
commands:
- '[ "${DRONE_TAG##v}" = "$$(python setup.py -V)" ]'
- python setup.py sdist bdist_wheel
when:
event: tag
tag: v*

pypi:
image: thomasf/twine
commands:
- twine upload dist/*
secrets: [ twine_username, twine_password ]
when:
event: tag
tag: v*


rebuild-cache:
image: drillster/drone-volume-cache
rebuild: true
mount:
- cache
- .tox
volumes:
- /tmp/drone-cache:/cache
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
.venv

# Installer logs
pip-log.txt
Expand Down
2 changes: 2 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[settings]
skip=.tox
29 changes: 26 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ Behind the scenes, it uses Roland Hedberg's great pyoidc library.

Modified by JHUAPL BOSS to support Python3

Modified by Thomas Frössman with fixes and additional modifications.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May create an AUTHORS file / add to NOTICE instead of including this information in the README.

This line breaks setup.py, as it includes a non-ascii character and setup.py reads this file without setting the encoding to UTF-8.


Quickstart
----------

Install djangooidc::

# Latest code - unstable!
pip install git+https://github.com/jhuapl-boss/django-oidc.git

pip install git+https://github.com/{desiredforkname}/django-oidc.git

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will want to keep our original version


(replace {desiredforkname} by the github username; find the fork which suit your needs, or just copy the name from your browser location field).

Then to use it in a Django project, add this to your urls.py::

url(r'openid/', include('djangooidc.urls')),
url(r'^openid/', include('djangooidc.urls')),


Then add the following items to your settings.py:
Expand Down Expand Up @@ -66,6 +69,26 @@ For example, an Azure AD OP would be::
You may now test the authentication by going to (on the development server) http://localhost:8000/openid/login or to any
of your views that requires authentication.

Using a private key jwt for client authentication
-------------------------------------------------
If you are using private keys for client authentication with the OP, you can specify it like::

OIDC_PROVIDERS = {
"mitreid": {
"srv_discovery_url": "https://mitreid.org/",
"behaviour": OIDC_DEFAULT_BEHAVIOUR,
"client_registration": {
"client_id": "your_client_id",
"redirect_uris": ["http://localhost:8000/openid/callback/login/"],
'token_endpoint_auth_method': ['private_key_jwt'],
"enc_kid": "rsa_test",
"keyset_jwk_file": "file://keys/keyset.jwk"
}
}
}

In this case keys/keyset.jwk is the full keyset (public and private keys) used when registering the client with the OP
manually. (I.E. you've provided the OP with the public key.)

Features
--------
Expand Down
76 changes: 54 additions & 22 deletions django_rp/settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Django settings for access_web project.
import os
import django

DEBUG = True
TEMPLATE_DEBUG = DEBUG
Expand Down Expand Up @@ -36,7 +37,7 @@

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-US'
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

Expand Down Expand Up @@ -95,13 +96,25 @@
'django.template.loaders.app_directories.Loader',
)

MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
if django.VERSION >= (2, 1):
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',
]
else:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)


SESSION_ENGINE = 'django.contrib.sessions.backends.db'

Expand All @@ -121,9 +134,28 @@

ROOT_URLCONF = 'django_rp.urls'

TEMPLATE_DIRS = (
# os.path.join(BASE_DIR, "django_rp/templates"),
)
if django.VERSION >= (2, 1):
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'djangooidc/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',
],
},
},
]
else:
TEMPLATE_DIRS = (
# os.path.join(BASE_DIR, "django_rp/templates"),
)

INSTALLED_APPS = (
'django.contrib.auth',
Expand Down Expand Up @@ -218,16 +250,16 @@
# The keys in this dictionary are the OPs (OpenID Providers) short user friendly name not the issuer (iss) name.
OIDC_PROVIDERS = {
# Test OP - webfinger supported on non-standard URL, no client self registration.
"Azure Active Directory": {
"srv_discovery_url": "https://sts.windows.net/9019caa7-f3ba-4261-8b4f-9162bdbe8cd1/",
"behaviour": OIDC_DEFAULT_BEHAVIOUR,
"client_registration": {
"client_id": "0d21f6d8-796f-4879-a2e1-314ddfcfb737",
"client_secret": "6hzvhNTsHPvTiUH/GUHVsFDt8b0BajZNox/iFI7iVJ8=",
"redirect_uris": ["http://localhost:8000/openid/callback/login/"],
"post_logout_redirect_uris": ["http://localhost:8000/openid/callback/logout/"],
}
},
# "Azure Active Directory": {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the full file, this comments out all OIDC providers. What was the reason for this, as it leaves the django_rp example in an incomplete state.

# "srv_discovery_url": "https://sts.windows.net/9019caa7-f3ba-4261-8b4f-9162bdbe8cd1/",
# "behaviour": OIDC_DEFAULT_BEHAVIOUR,
# "client_registration": {
# "client_id": "0d21f6d8-796f-4879-a2e1-314ddfcfb737",
# "client_secret": "6hzvhNTsHPvTiUH/GUHVsFDt8b0BajZNox/iFI7iVJ8=",
# "redirect_uris": ["http://localhost:8000/openid/callback/login/"],
# "post_logout_redirect_uris": ["http://localhost:8000/openid/callback/logout/"],
# }
# },
# # No webfinger support, but OP information lookup and client registration
# "xenosmilus": {
# "srv_discovery_url": "https://xenosmilus2.umdc.umu.se:8091/",
Expand Down Expand Up @@ -283,4 +315,4 @@
# },
}
#
###############################################################################
###############################################################################
26 changes: 14 additions & 12 deletions django_rp/urls.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
from django.conf.urls import patterns, include, url
from os import path

from django.conf.urls import include, url
from django.contrib import admin

from testapp.views import home, unprotected

admin.autodiscover()

from os import path

BASEDIR = path.dirname(path.abspath(__file__))

urlpatterns = patterns('',
# URLS for OpenId authentication
url(r'openid/', include('djangooidc.urls')),

# Test URLs
url(r'^$', 'testapp.views.home', name='home'),
url(r'^unprotected$', 'testapp.views.unprotected', name='unprotected'),
urlpatterns = [
# URLS for OpenId authentication
url(r'^openid/', include('djangooidc.urls')),

# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
# Test URLs
url(r'^$', home, name='home'),
url(r'^unprotected$', unprotected, name='unprotected'),

)
# Uncomment the next line to enable the admin:
url(r'^admin/', admin.site.urls),
]
9 changes: 5 additions & 4 deletions django_rp/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
import os
import sys

# This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here.
from django.core.wsgi import get_wsgi_application

mage_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), os.path.pardir)
if mage_path not in sys.path:
sys.path.append(mage_path)
Expand All @@ -28,10 +33,6 @@
# os.environ["DJANGO_SETTINGS_MODULE"] = "MAGE2.settings"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MAGE.settings")

# This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

# Apply WSGI middleware here.
Expand Down
2 changes: 1 addition & 1 deletion djangooidc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# coding: utf-8

__version__ = '0.1.3'
__version__ = '0.0.9'
30 changes: 18 additions & 12 deletions djangooidc/backends.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# coding: utf-8

from __future__ import unicode_literals
import datetime

from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.utils import timezone


class OpenIdConnectBackend(ModelBackend):
"""
This backend checks a previously performed OIDC authentication.
If it is OK and the user already exists in the database, it is returned.
If it is OK and user does not exist in the database, it is created and returned unless setting
OIDC_CREATE_UNKNOWN_USER is False.
If it is OK and user does not exist in the database, it is created and
returned unless setting OIDC_CREATE_UNKNOWN_USER is False.
In all other cases, None is returned.
"""

def authenticate(self, **kwargs):
def authenticate(self, request, **kwargs):
user = None
if not kwargs or 'sub' not in kwargs.keys():
return user
Expand All @@ -26,8 +26,9 @@ def authenticate(self, **kwargs):
if 'upn' in kwargs.keys():
username = kwargs['upn']

# Some OP may actually choose to withhold some information, so we must test if it is present
openid_data = {'last_login': datetime.datetime.now()}
# Some OP may actually choose to withhold some information, so we must
# test if it is present
openid_data = {'last_login': timezone.now()}
if 'first_name' in kwargs.keys():
openid_data['first_name'] = kwargs['first_name']
if 'given_name' in kwargs.keys():
Expand All @@ -45,15 +46,19 @@ def authenticate(self, **kwargs):
# instead we use get_or_create when creating unknown users since it has
# built-in safeguards for multiple threads.
if getattr(settings, 'OIDC_CREATE_UNKNOWN_USER', True):
args = {UserModel.USERNAME_FIELD: username, 'defaults': openid_data, }
args = {UserModel.USERNAME_FIELD: username,
'defaults': openid_data, }
user, created = UserModel.objects.update_or_create(**args)
if created:
user = self.configure_user(user)
user = self.configure_user(user, **kwargs)
else:
try:
user = UserModel.objects.get_by_natural_key(username)
except UserModel.DoesNotExist:
return None
try:
user = UserModel.objects.get(email=kwargs['email'])
except UserModel.DoesNotExist:
return None
return user

def clean_username(self, username):
Expand All @@ -65,10 +70,11 @@ def clean_username(self, username):
"""
return username

def configure_user(self, user):
def configure_user(self, user, **kwargs):
"""
Configures a user after creation and returns the updated user.

By default, returns the user unmodified.
"""
return user
user.set_unusable_password()
return user
Loading