From 2f54e537666c689dd8448f8bbc6a3a0244b01a97 Mon Sep 17 00:00:00 2001 From: John Kristensen Date: Wed, 13 Apr 2016 18:14:59 +1000 Subject: [PATCH 1/7] Ensure client redirect URIs with query strings work In some cases a client will provide a redirect URI with a query string. In these cases the client redirect URI should still still match a registered redirect URI and not result in a failure. --- oidc_provider/lib/endpoints/token.py | 3 ++- oidc_provider/tests/test_token_endpoint.py | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/oidc_provider/lib/endpoints/token.py b/oidc_provider/lib/endpoints/token.py index 2a687f5..b12ecaf 100644 --- a/oidc_provider/lib/endpoints/token.py +++ b/oidc_provider/lib/endpoints/token.py @@ -33,7 +33,8 @@ class TokenEndpoint(object): self.params.client_id = client_id self.params.client_secret = client_secret - self.params.redirect_uri = unquote(self.request.POST.get('redirect_uri', '')) + self.params.redirect_uri = unquote( + self.request.POST.get('redirect_uri', '').split('?', 1)[0]) self.params.grant_type = self.request.POST.get('grant_type', '') self.params.code = self.request.POST.get('code', '') self.params.state = self.request.POST.get('state', '') diff --git a/oidc_provider/tests/test_token_endpoint.py b/oidc_provider/tests/test_token_endpoint.py index 652d8ad..bdafb48 100644 --- a/oidc_provider/tests/test_token_endpoint.py +++ b/oidc_provider/tests/test_token_endpoint.py @@ -271,6 +271,29 @@ class TokenTestCase(TestCase): False, msg='Client authentication fails using HTTP Basic Auth.') + def test_client_redirect_url(self): + """ + Validate that client redirect URIs with query strings match registered + URIs, and that unregistered URIs are rejected. + """ + SIGKEYS = self._get_keys() + code = self._create_code() + post_data = self._auth_code_post_data(code=code.code) + + # Unregistered URI + post_data['redirect_uri'] = 'http://invalid.example.org' + + response = self._post_request(post_data) + + self.assertIn('invalid_client', response.content.decode('utf-8')), + + # Registered URI contained a query string + post_data['redirect_uri'] = 'http://example.com/?client=OidcClient' + + response = self._post_request(post_data) + + self.assertNotIn('invalid_client', response.content.decode('utf-8')), + def test_access_token_contains_nonce(self): """ If present in the Authentication Request, Authorization Servers MUST From f9990d8b345b698363887494ff3801b7e92a62a8 Mon Sep 17 00:00:00 2001 From: Ignacio Fiorentino Date: Wed, 5 Oct 2016 14:18:38 -0300 Subject: [PATCH 2/7] Fix docs. --- docs/sections/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sections/installation.rst b/docs/sections/installation.rst index 59b5e10..53db3ed 100644 --- a/docs/sections/installation.rst +++ b/docs/sections/installation.rst @@ -41,8 +41,8 @@ Add the provider urls:: Generate server RSA key and run migrations (if you don't):: - $ python manage.py creatersakey $ python manage.py migrate + $ python manage.py creatersakey Add required variables to your project settings:: From 2cedde5e3f88eed124d2aa27d16dcafe02df99c8 Mon Sep 17 00:00:00 2001 From: Ignacio Fiorentino Date: Tue, 11 Oct 2016 13:18:06 -0300 Subject: [PATCH 3/7] Remove spaces. --- oidc_provider/lib/utils/common.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/oidc_provider/lib/utils/common.py b/oidc_provider/lib/utils/common.py index 2c4971c..7e1fd28 100644 --- a/oidc_provider/lib/utils/common.py +++ b/oidc_provider/lib/utils/common.py @@ -17,9 +17,7 @@ def cleanup_url_from_query_string(uri): :type uri: str :return: cleaned URI without query string """ - clean_uri = urlsplit(uri) - # noinspection PyProtectedMember clean_uri = urlunsplit(clean_uri._replace(query='')) return clean_uri From 7b07a398a49a8f6b2f1abde6b86686d6192cdf01 Mon Sep 17 00:00:00 2001 From: Ignacio Fiorentino Date: Tue, 11 Oct 2016 13:32:28 -0300 Subject: [PATCH 4/7] Edit CHANGELOG. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeb57bf..1ed034f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. ### [Unreleased] +##### Added +- Support for client redirect URIs with query strings. + ### [0.4.1] - 2016-10-03 ##### Changed From 7405d79fdba7ff1ad1324d54a6579cdfb708c72e Mon Sep 17 00:00:00 2001 From: Ignacio Fiorentino Date: Wed, 12 Oct 2016 11:11:04 -0300 Subject: [PATCH 5/7] Edit CHANGELOG. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed034f..664f93d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ All notable changes to this project will be documented in this file. ##### Added - Support for client redirect URIs with query strings. +##### Fixed +- Bug when generating secret_key value using admin. + ### [0.4.1] - 2016-10-03 ##### Changed From 99d7194ab1a578d37ac40c71fa58a28187568568 Mon Sep 17 00:00:00 2001 From: David Montano Date: Wed, 12 Oct 2016 14:23:57 -0500 Subject: [PATCH 6/7] Make Client available when using OIDC_EXTRA_SCOPE_CLAIMS Now it's passed the Token to the ScopeClaims constructor so that it can make Client avaialble to implementors --- CHANGELOG.md | 6 ++++++ docs/sections/scopesclaims.rst | 1 + oidc_provider/lib/claims.py | 7 ++++--- oidc_provider/tests/app/utils.py | 15 ++++++++++++++- oidc_provider/tests/test_claims.py | 7 +++++-- oidc_provider/views.py | 4 ++-- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 664f93d..5599488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ All notable changes to this project will be documented in this file. ##### Fixed - Bug when generating secret_key value using admin. +##### Changed +- Client is available to OIDC_EXTRA_SCOPE_CLAIMS implementations via `self.client`. + +##### Incompatible changes +- The constructor signature for `ScopeClaims` has changed, it now is called with the `Token` as its single argument. + ### [0.4.1] - 2016-10-03 ##### Changed diff --git a/docs/sections/scopesclaims.rst b/docs/sections/scopesclaims.rst index 1973f74..58481f3 100644 --- a/docs/sections/scopesclaims.rst +++ b/docs/sections/scopesclaims.rst @@ -96,6 +96,7 @@ Inside your oidc_provider_settings.py file add the following class:: # self.user - Django user instance. # self.userinfo - Dict returned by OIDC_USERINFO function. # self.scopes - List of scopes requested. + # self.client - Client requesting this claims. dic = { 'bar': 'Something dynamic here', } diff --git a/oidc_provider/lib/claims.py b/oidc_provider/lib/claims.py index 16e3919..a958455 100644 --- a/oidc_provider/lib/claims.py +++ b/oidc_provider/lib/claims.py @@ -14,10 +14,11 @@ STANDARD_CLAIMS = { class ScopeClaims(object): - def __init__(self, user, scopes): - self.user = user + def __init__(self, token): + self.user = token.user self.userinfo = settings.get('OIDC_USERINFO', import_str=True)(STANDARD_CLAIMS, self.user) - self.scopes = scopes + self.scopes = token.scope + self.client = token.client def create_response_dic(self): """ diff --git a/oidc_provider/tests/app/utils.py b/oidc_provider/tests/app/utils.py index 6308d1b..68ad7ba 100644 --- a/oidc_provider/tests/app/utils.py +++ b/oidc_provider/tests/app/utils.py @@ -1,16 +1,19 @@ import random import string + + try: from urlparse import parse_qs, urlsplit except ImportError: from urllib.parse import parse_qs, urlsplit +from django.utils import timezone from django.contrib.auth.models import User from oidc_provider.models import ( Client, Code, -) + Token) FAKE_NONCE = 'cb584e44c43ed6bd0bc2d9c7e242837d' @@ -58,6 +61,16 @@ def create_fake_client(response_type, is_public=False): return client +def create_fake_token(user, scopes, client): + expires_at = timezone.now() + timezone.timedelta(seconds=60) + token = Token(user=user, client=client, expires_at=expires_at) + token.scope = scopes + + token.save() + + return token + + def is_code_valid(url, user, client): """ Check if the code inside the url is valid. Supporting both query string and fragment. diff --git a/oidc_provider/tests/test_claims.py b/oidc_provider/tests/test_claims.py index 92429b3..ae105a1 100644 --- a/oidc_provider/tests/test_claims.py +++ b/oidc_provider/tests/test_claims.py @@ -1,6 +1,7 @@ from django.test import TestCase + from oidc_provider.lib.claims import ScopeClaims -from oidc_provider.tests.app.utils import create_fake_user +from oidc_provider.tests.app.utils import create_fake_user, create_fake_client, create_fake_token class ClaimsTestCase(TestCase): @@ -8,7 +9,9 @@ class ClaimsTestCase(TestCase): def setUp(self): self.user = create_fake_user() self.scopes = ['openid', 'address', 'email', 'phone', 'profile'] - self.scopeClaims = ScopeClaims(self.user, self.scopes) + self.client = create_fake_client('code') + self.token = create_fake_token(self.user, self.scopes, self.client) + self.scopeClaims = ScopeClaims(self.token) def test_clean_dic(self): """ assert that _clean_dic function returns a clean dictionnary diff --git a/oidc_provider/views.py b/oidc_provider/views.py index 427a1e5..91b96a4 100644 --- a/oidc_provider/views.py +++ b/oidc_provider/views.py @@ -162,11 +162,11 @@ def userinfo(request, *args, **kwargs): 'sub': token.id_token.get('sub'), } - standard_claims = StandardScopeClaims(token.user, token.scope) + standard_claims = StandardScopeClaims(token) dic.update(standard_claims.create_response_dic()) if settings.get('OIDC_EXTRA_SCOPE_CLAIMS'): - extra_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(token.user, token.scope) + extra_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(token) dic.update(extra_claims.create_response_dic()) response = JsonResponse(dic, status=200) From 76dca8f504a776281155a6bbf8d7d333ee796e1d Mon Sep 17 00:00:00 2001 From: Ignacio Fiorentino Date: Thu, 13 Oct 2016 11:31:33 -0300 Subject: [PATCH 7/7] Bump version v0.4.2. --- CHANGELOG.md | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5599488..82c58f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. ### [Unreleased] +### [0.4.2] - 2016-10-13 + ##### Added - Support for client redirect URIs with query strings. @@ -12,8 +14,6 @@ All notable changes to this project will be documented in this file. ##### Changed - Client is available to OIDC_EXTRA_SCOPE_CLAIMS implementations via `self.client`. - -##### Incompatible changes - The constructor signature for `ScopeClaims` has changed, it now is called with the `Token` as its single argument. ### [0.4.1] - 2016-10-03 diff --git a/setup.py b/setup.py index 851de13..78acf07 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) setup( name='django-oidc-provider', - version='0.4.1', + version='0.4.2', packages=[ 'oidc_provider', 'oidc_provider/lib', 'oidc_provider/lib/endpoints', 'oidc_provider/lib/utils', 'oidc_provider/tests', 'oidc_provider/tests/app',