diff --git a/mozilla_django_oidc/auth.py b/mozilla_django_oidc/auth.py index f8243fe3..383108df 100644 --- a/mozilla_django_oidc/auth.py +++ b/mozilla_django_oidc/auth.py @@ -17,7 +17,7 @@ from requests.auth import HTTPBasicAuth from requests.exceptions import HTTPError -from mozilla_django_oidc.utils import absolutify, import_from_settings +from mozilla_django_oidc.utils import absolutify, get_setting LOGGER = logging.getLogger(__name__) @@ -47,13 +47,13 @@ class OIDCAuthenticationBackend(ModelBackend): def __init__(self, *args, **kwargs): """Initialize settings.""" - self.OIDC_OP_TOKEN_ENDPOINT = self.get_settings("OIDC_OP_TOKEN_ENDPOINT") - self.OIDC_OP_USER_ENDPOINT = self.get_settings("OIDC_OP_USER_ENDPOINT") - self.OIDC_OP_JWKS_ENDPOINT = self.get_settings("OIDC_OP_JWKS_ENDPOINT", None) - self.OIDC_RP_CLIENT_ID = self.get_settings("OIDC_RP_CLIENT_ID") - self.OIDC_RP_CLIENT_SECRET = self.get_settings("OIDC_RP_CLIENT_SECRET") - self.OIDC_RP_SIGN_ALGO = self.get_settings("OIDC_RP_SIGN_ALGO", "HS256") - self.OIDC_RP_IDP_SIGN_KEY = self.get_settings("OIDC_RP_IDP_SIGN_KEY", None) + self.OIDC_OP_TOKEN_ENDPOINT = get_setting("OIDC_OP_TOKEN_ENDPOINT") + self.OIDC_OP_USER_ENDPOINT = get_setting("OIDC_OP_USER_ENDPOINT") + self.OIDC_OP_JWKS_ENDPOINT = get_setting("OIDC_OP_JWKS_ENDPOINT", None) + self.OIDC_RP_CLIENT_ID = get_setting("OIDC_RP_CLIENT_ID") + self.OIDC_RP_CLIENT_SECRET = get_setting("OIDC_RP_CLIENT_SECRET") + self.OIDC_RP_SIGN_ALGO = get_setting("OIDC_RP_SIGN_ALGO", "HS256") + self.OIDC_RP_IDP_SIGN_KEY = get_setting("OIDC_RP_IDP_SIGN_KEY", None) if ( self.OIDC_RP_SIGN_ALGO.startswith("RS") @@ -66,10 +66,6 @@ def __init__(self, *args, **kwargs): self.UserModel = get_user_model() - @staticmethod - def get_settings(attr, *args): - return import_from_settings(attr, *args) - def describe_user_by_claims(self, claims): email = claims.get("email") return "email {}".format(email) @@ -85,7 +81,7 @@ def verify_claims(self, claims): """Verify the provided claims to decide if authentication should be allowed.""" # Verify claims required by default configuration - scopes = self.get_settings("OIDC_RP_SCOPES", "openid email") + scopes = get_setting("OIDC_RP_SCOPES", "openid email") if "email" in scopes.split(): return "email" in claims @@ -107,7 +103,7 @@ def get_username(self, claims): # bluntly stolen from django-browserid # https://github.com/mozilla/django-browserid/blob/master/django_browserid/auth.py - username_algo = self.get_settings("OIDC_USERNAME_ALGO", None) + username_algo = get_setting("OIDC_USERNAME_ALGO", None) if username_algo: if isinstance(username_algo, str): @@ -159,9 +155,9 @@ def retrieve_matching_jwk(self, token): """Get the signing key by exploring the JWKS endpoint of the OP.""" response_jwks = requests.get( self.OIDC_OP_JWKS_ENDPOINT, - verify=self.get_settings("OIDC_VERIFY_SSL", True), - timeout=self.get_settings("OIDC_TIMEOUT", None), - proxies=self.get_settings("OIDC_PROXY", None), + verify=get_setting("OIDC_VERIFY_SSL", True), + timeout=get_setting("OIDC_TIMEOUT", None), + proxies=get_setting("OIDC_PROXY", None), ) response_jwks.raise_for_status() jwks = response_jwks.json() @@ -173,9 +169,9 @@ def retrieve_matching_jwk(self, token): key = None for jwk in jwks["keys"]: - if import_from_settings("OIDC_VERIFY_KID", True) and jwk[ - "kid" - ] != smart_str(header.kid): + if get_setting("OIDC_VERIFY_KID", True) and jwk["kid"] != smart_str( + header.kid + ): continue if "alg" in jwk and jwk["alg"] != smart_str(header.alg): continue @@ -186,7 +182,7 @@ def retrieve_matching_jwk(self, token): def get_payload_data(self, token, key): """Helper method to get the payload of the JWT token.""" - if self.get_settings("OIDC_ALLOW_UNSECURED_JWT", False): + if get_setting("OIDC_ALLOW_UNSECURED_JWT", False): header, payload_data, signature = token.split(b".") header = json.loads(smart_str(b64decode(header))) @@ -224,7 +220,7 @@ def verify_token(self, token, **kwargs): payload = json.loads(payload_data.decode("utf-8")) token_nonce = payload.get("nonce") - if self.get_settings("OIDC_USE_NONCE", True) and nonce != token_nonce: + if get_setting("OIDC_USE_NONCE", True) and nonce != token_nonce: msg = "JWT Nonce verification failed." raise SuspiciousOperation(msg) return payload @@ -233,7 +229,7 @@ def get_token(self, payload): """Return token object as a dictionary.""" auth = None - if self.get_settings("OIDC_TOKEN_USE_BASIC_AUTH", False): + if get_setting("OIDC_TOKEN_USE_BASIC_AUTH", False): # When Basic auth is defined, create the Auth Header and remove secret from payload. user = payload.get("client_id") pw = payload.get("client_secret") @@ -245,9 +241,9 @@ def get_token(self, payload): self.OIDC_OP_TOKEN_ENDPOINT, data=payload, auth=auth, - verify=self.get_settings("OIDC_VERIFY_SSL", True), - timeout=self.get_settings("OIDC_TIMEOUT", None), - proxies=self.get_settings("OIDC_PROXY", None), + verify=get_setting("OIDC_VERIFY_SSL", True), + timeout=get_setting("OIDC_TIMEOUT", None), + proxies=get_setting("OIDC_PROXY", None), ) self.raise_token_response_error(response) return response.json() @@ -274,9 +270,9 @@ def get_userinfo(self, access_token, id_token, payload): user_response = requests.get( self.OIDC_OP_USER_ENDPOINT, headers={"Authorization": "Bearer {0}".format(access_token)}, - verify=self.get_settings("OIDC_VERIFY_SSL", True), - timeout=self.get_settings("OIDC_TIMEOUT", None), - proxies=self.get_settings("OIDC_PROXY", None), + verify=get_setting("OIDC_VERIFY_SSL", True), + timeout=get_setting("OIDC_TIMEOUT", None), + proxies=get_setting("OIDC_PROXY", None), ) user_response.raise_for_status() return user_response.json() @@ -296,7 +292,7 @@ def authenticate(self, request, **kwargs): if not code or not state: return None - reverse_url = self.get_settings( + reverse_url = get_setting( "OIDC_AUTHENTICATION_CALLBACK_URL", "oidc_authentication_callback" ) @@ -334,10 +330,10 @@ def store_tokens(self, access_token, id_token): """Store OIDC tokens.""" session = self.request.session - if self.get_settings("OIDC_STORE_ACCESS_TOKEN", False): + if get_setting("OIDC_STORE_ACCESS_TOKEN", False): session["oidc_access_token"] = access_token - if self.get_settings("OIDC_STORE_ID_TOKEN", False): + if get_setting("OIDC_STORE_ID_TOKEN", False): session["oidc_id_token"] = id_token def get_or_create_user(self, access_token, id_token, payload): @@ -361,7 +357,7 @@ def get_or_create_user(self, access_token, id_token, payload): # bail. Randomly selecting one seems really wrong. msg = "Multiple users returned" raise SuspiciousOperation(msg) - elif self.get_settings("OIDC_CREATE_USER", True): + elif get_setting("OIDC_CREATE_USER", True): user = self.create_user(user_info) return user else: diff --git a/mozilla_django_oidc/contrib/drf.py b/mozilla_django_oidc/contrib/drf.py index 91f8ccc5..85dbccc0 100644 --- a/mozilla_django_oidc/contrib/drf.py +++ b/mozilla_django_oidc/contrib/drf.py @@ -14,7 +14,7 @@ from mozilla_django_oidc.auth import OIDCAuthenticationBackend from mozilla_django_oidc.utils import ( - import_from_settings, + get_setting, parse_www_authenticate_header, ) @@ -29,7 +29,7 @@ def get_oidc_backend(): # allow the user to force which back backend to use. this is mostly # convenient if you want to use OIDC with DRF but don't want to configure # OIDC for the "normal" Django auth. - backend_setting = import_from_settings("OIDC_DRF_AUTH_BACKEND", None) + backend_setting = get_setting("OIDC_DRF_AUTH_BACKEND", None) if backend_setting: backend = import_string(backend_setting)() if not isinstance(backend, OIDCAuthenticationBackend): diff --git a/mozilla_django_oidc/middleware.py b/mozilla_django_oidc/middleware.py index 1b050325..ac77e63a 100644 --- a/mozilla_django_oidc/middleware.py +++ b/mozilla_django_oidc/middleware.py @@ -1,21 +1,19 @@ import logging import time from re import Pattern as re_Pattern -from urllib.parse import quote, urlencode +from urllib.parse import quote from django.contrib.auth import BACKEND_SESSION_KEY from django.http import HttpResponseRedirect, JsonResponse from django.urls import reverse -from django.utils.crypto import get_random_string from django.utils.deprecation import MiddlewareMixin from django.utils.functional import cached_property from django.utils.module_loading import import_string from mozilla_django_oidc.auth import OIDCAuthenticationBackend from mozilla_django_oidc.utils import ( - absolutify, - add_state_and_verifier_and_nonce_to_session, - import_from_settings, + get_url_for_authorization_code_request, + get_setting, ) LOGGER = logging.getLogger(__name__) @@ -31,23 +29,7 @@ class SessionRefresh(MiddlewareMixin): def __init__(self, get_response): super(SessionRefresh, self).__init__(get_response) - self.OIDC_EXEMPT_URLS = self.get_settings("OIDC_EXEMPT_URLS", []) - self.OIDC_OP_AUTHORIZATION_ENDPOINT = self.get_settings( - "OIDC_OP_AUTHORIZATION_ENDPOINT" - ) - self.OIDC_RP_CLIENT_ID = self.get_settings("OIDC_RP_CLIENT_ID") - self.OIDC_STATE_SIZE = self.get_settings("OIDC_STATE_SIZE", 32) - self.OIDC_AUTHENTICATION_CALLBACK_URL = self.get_settings( - "OIDC_AUTHENTICATION_CALLBACK_URL", - "oidc_authentication_callback", - ) - self.OIDC_RP_SCOPES = self.get_settings("OIDC_RP_SCOPES", "openid email") - self.OIDC_USE_NONCE = self.get_settings("OIDC_USE_NONCE", True) - self.OIDC_NONCE_SIZE = self.get_settings("OIDC_NONCE_SIZE", 32) - - @staticmethod - def get_settings(attr, *args): - return import_from_settings(attr, *args) + self.OIDC_EXEMPT_URLS = get_setting("OIDC_EXEMPT_URLS", []) @cached_property def exempt_urls(self): @@ -98,7 +80,6 @@ def is_refreshable_url(self, request): :arg HttpRequest request: :returns: boolean - """ # Do not attempt to refresh the session if the OIDC backend is not used backend_session = request.session.get(BACKEND_SESSION_KEY) @@ -129,35 +110,11 @@ def process_request(self, request): LOGGER.debug("id token has expired") # The id_token has expired, so we have to re-authenticate silently. - auth_url = self.OIDC_OP_AUTHORIZATION_ENDPOINT - client_id = self.OIDC_RP_CLIENT_ID - state = get_random_string(self.OIDC_STATE_SIZE) - - # Build the parameters as if we were doing a real auth handoff, except - # we also include prompt=none. - params = { - "response_type": "code", - "client_id": client_id, - "redirect_uri": absolutify( - request, reverse(self.OIDC_AUTHENTICATION_CALLBACK_URL) - ), - "state": state, - "scope": self.OIDC_RP_SCOPES, - "prompt": "none", - } - - params.update(self.get_settings("OIDC_AUTH_REQUEST_EXTRA_PARAMS", {})) - - if self.OIDC_USE_NONCE: - nonce = get_random_string(self.OIDC_NONCE_SIZE) - params.update({"nonce": nonce}) - - add_state_and_verifier_and_nonce_to_session(request, state, params) - request.session["oidc_login_next"] = request.get_full_path() + redirect_url = get_url_for_authorization_code_request( + request, prompt=False, quote_params_via=quote + ) - query = urlencode(params, quote_via=quote) - redirect_url = "{url}?{query}".format(url=auth_url, query=query) if request.headers.get("x-requested-with") == "XMLHttpRequest": # Almost all XHR request handling in client-side code struggles # with redirects since redirecting to a page where the user diff --git a/mozilla_django_oidc/urls.py b/mozilla_django_oidc/urls.py index e6dcc4ad..ebe5da97 100644 --- a/mozilla_django_oidc/urls.py +++ b/mozilla_django_oidc/urls.py @@ -2,18 +2,16 @@ from django.utils.module_loading import import_string from mozilla_django_oidc import views -from mozilla_django_oidc.utils import import_from_settings +from mozilla_django_oidc.utils import get_setting DEFAULT_CALLBACK_CLASS = "mozilla_django_oidc.views.OIDCAuthenticationCallbackView" -CALLBACK_CLASS_PATH = import_from_settings( - "OIDC_CALLBACK_CLASS", DEFAULT_CALLBACK_CLASS -) +CALLBACK_CLASS_PATH = get_setting("OIDC_CALLBACK_CLASS", DEFAULT_CALLBACK_CLASS) OIDCCallbackClass = import_string(CALLBACK_CLASS_PATH) DEFAULT_AUTHENTICATE_CLASS = "mozilla_django_oidc.views.OIDCAuthenticationRequestView" -AUTHENTICATE_CLASS_PATH = import_from_settings( +AUTHENTICATE_CLASS_PATH = get_setting( "OIDC_AUTHENTICATE_CLASS", DEFAULT_AUTHENTICATE_CLASS ) diff --git a/mozilla_django_oidc/utils.py b/mozilla_django_oidc/utils.py index 6e70ee95..e81ac9bf 100644 --- a/mozilla_django_oidc/utils.py +++ b/mozilla_django_oidc/utils.py @@ -2,12 +2,16 @@ import time import warnings from hashlib import sha256 +from urllib.parse import quote_plus, urlencode from urllib.request import parse_http_list, parse_keqv_list # Make it obvious that these aren't the usual base64 functions import josepy.b64 from django.conf import settings from django.core.exceptions import ImproperlyConfigured +from django.urls import reverse +from django.utils.crypto import get_random_string + LOGGER = logging.getLogger(__name__) @@ -21,7 +25,7 @@ def parse_www_authenticate_header(header): return parse_keqv_list(items) -def import_from_settings(attr, *args): +def get_setting(attr, *args): """ Load an attribute from the django settings. @@ -139,7 +143,7 @@ def add_state_and_verifier_and_nonce_to_session( # If the number of State/Nonce combinations reaches a certain threshold, remove the oldest # state by finding out # which element has the oldest "add_on" time. - limit = import_from_settings("OIDC_MAX_STATES", 50) + limit = get_setting("OIDC_MAX_STATES", 50) if len(request.session["oidc_states"]) >= limit: LOGGER.info( 'User has more than {} "oidc_states" in his session, ' @@ -159,3 +163,69 @@ def add_state_and_verifier_and_nonce_to_session( "nonce": nonce, "added_on": time.time(), } + + +def get_url_for_authorization_code_request( + request, prompt=True, quote_params_via=quote_plus +): + """ + Builds and returns the URL required for the authorization code request, and + also adds the state, nonce, and code verifier (if using PKCE) to the session. + """ + OIDC_AUTHENTICATION_CALLBACK_URL = get_setting( + "OIDC_AUTHENTICATION_CALLBACK_URL", + "oidc_authentication_callback", + ) + + state = get_random_string(get_setting("OIDC_STATE_SIZE", 32)) + + params = { + "response_type": "code", + "client_id": get_setting("OIDC_RP_CLIENT_ID"), + "scope": get_setting("OIDC_RP_SCOPES", "openid email"), + "redirect_uri": absolutify(request, reverse(OIDC_AUTHENTICATION_CALLBACK_URL)), + "state": state, + } + + if not prompt: + params.update(prompt="none") + + params.update(get_setting("OIDC_AUTH_REQUEST_EXTRA_PARAMS", {})) + + if get_setting("OIDC_USE_NONCE", True): + params.update(nonce=get_random_string(get_setting("OIDC_NONCE_SIZE", 32))) + + if get_setting("OIDC_USE_PKCE", False): + OIDC_PKCE_CODE_VERIFIER_SIZE = get_setting("OIDC_PKCE_CODE_VERIFIER_SIZE", 64) + + if not (43 <= OIDC_PKCE_CODE_VERIFIER_SIZE <= 128): + # Check that OIDC_PKCE_CODE_VERIFIER_SIZE is between the min and max length + # defined in https://datatracker.ietf.org/doc/html/rfc7636#section-4.1 + raise ImproperlyConfigured( + "OIDC_PKCE_CODE_VERIFIER_SIZE must be between 43 and 128" + ) + + OIDC_PKCE_CODE_CHALLENGE_METHOD = get_setting( + "OIDC_PKCE_CODE_CHALLENGE_METHOD", "S256" + ) + + if OIDC_PKCE_CODE_CHALLENGE_METHOD not in ("plain", "S256"): + raise ImproperlyConfigured( + "OIDC_PKCE_CODE_CHALLENGE_METHOD must be 'plain' or 'S256'" + ) + + code_verifier = get_random_string(OIDC_PKCE_CODE_VERIFIER_SIZE) + params.update( + code_challenge=generate_code_challenge( + code_verifier, OIDC_PKCE_CODE_CHALLENGE_METHOD + ), + code_challenge_method=OIDC_PKCE_CODE_CHALLENGE_METHOD, + ) + else: + code_verifier = None + + add_state_and_verifier_and_nonce_to_session(request, state, params, code_verifier) + + query_params = urlencode(params, quote_via=quote_params_via) + + return f"{get_setting('OIDC_OP_AUTHORIZATION_ENDPOINT')}?{query_params}" diff --git a/mozilla_django_oidc/views.py b/mozilla_django_oidc/views.py index 0f05b8b2..0aba9500 100644 --- a/mozilla_django_oidc/views.py +++ b/mozilla_django_oidc/views.py @@ -1,21 +1,16 @@ import time -from urllib.parse import urlencode from django.contrib import auth from django.core.exceptions import SuspiciousOperation from django.http import HttpResponseNotAllowed, HttpResponseRedirect from django.shortcuts import resolve_url -from django.urls import reverse -from django.utils.crypto import get_random_string from django.utils.http import url_has_allowed_host_and_scheme from django.utils.module_loading import import_string from django.views.generic import View from mozilla_django_oidc.utils import ( - absolutify, - add_state_and_verifier_and_nonce_to_session, - generate_code_challenge, - import_from_settings, + get_url_for_authorization_code_request, + get_setting, ) @@ -24,20 +19,16 @@ class OIDCAuthenticationCallbackView(View): http_method_names = ["get"] - @staticmethod - def get_settings(attr, *args): - return import_from_settings(attr, *args) - @property def failure_url(self): - return self.get_settings("LOGIN_REDIRECT_URL_FAILURE", "/") + return get_setting("LOGIN_REDIRECT_URL_FAILURE", "/") @property def success_url(self): # Pull the next url from the session or settings--we don't need to # sanitize here because it should already have been sanitized. next_url = self.request.session.get("oidc_login_next", None) - return next_url or resolve_url(self.get_settings("LOGIN_REDIRECT_URL", "/")) + return next_url or resolve_url(get_setting("LOGIN_REDIRECT_URL", "/")) def login_failure(self): return HttpResponseRedirect(self.failure_url) @@ -55,9 +46,7 @@ def login_success(self): # Figure out when this id_token will expire. This is ignored unless you're # using the SessionRefresh middleware. - expiration_interval = self.get_settings( - "OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS", 60 * 15 - ) + expiration_interval = get_setting("OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS", 60 * 15) self.request.session["oidc_id_token_expiration"] = ( time.time() + expiration_interval ) @@ -144,12 +133,12 @@ def get_next_url(request, redirect_field_name): if next_url: kwargs = { "url": next_url, - "require_https": import_from_settings( + "require_https": get_setting( "OIDC_REDIRECT_REQUIRE_HTTPS", request.is_secure() ), } - hosts = list(import_from_settings("OIDC_REDIRECT_ALLOWED_HOSTS", [])) + hosts = list(get_setting("OIDC_REDIRECT_ALLOWED_HOSTS", [])) hosts.append(request.get_host()) kwargs["allowed_hosts"] = hosts @@ -164,94 +153,23 @@ class OIDCAuthenticationRequestView(View): http_method_names = ["get"] - def __init__(self, *args, **kwargs): - super(OIDCAuthenticationRequestView, self).__init__(*args, **kwargs) - - self.OIDC_OP_AUTH_ENDPOINT = self.get_settings("OIDC_OP_AUTHORIZATION_ENDPOINT") - self.OIDC_RP_CLIENT_ID = self.get_settings("OIDC_RP_CLIENT_ID") - - @staticmethod - def get_settings(attr, *args): - return import_from_settings(attr, *args) - def get(self, request): """OIDC client authentication initialization HTTP endpoint""" - state = get_random_string(self.get_settings("OIDC_STATE_SIZE", 32)) - redirect_field_name = self.get_settings("OIDC_REDIRECT_FIELD_NAME", "next") - reverse_url = self.get_settings( - "OIDC_AUTHENTICATION_CALLBACK_URL", "oidc_authentication_callback" - ) - - params = { - "response_type": "code", - "scope": self.get_settings("OIDC_RP_SCOPES", "openid email"), - "client_id": self.OIDC_RP_CLIENT_ID, - "redirect_uri": absolutify(request, reverse(reverse_url)), - "state": state, - } - - params.update(self.get_extra_params(request)) - - if self.get_settings("OIDC_USE_NONCE", True): - nonce = get_random_string(self.get_settings("OIDC_NONCE_SIZE", 32)) - params.update({"nonce": nonce}) - - if self.get_settings("OIDC_USE_PKCE", False): - code_verifier_length = self.get_settings("OIDC_PKCE_CODE_VERIFIER_SIZE", 64) - # Check that code_verifier_length is between the min and max length - # defined in https://datatracker.ietf.org/doc/html/rfc7636#section-4.1 - if not (43 <= code_verifier_length <= 128): - raise ValueError("code_verifier_length must be between 43 and 128") - - # Generate code_verifier and code_challenge pair - code_verifier = get_random_string(code_verifier_length) - code_challenge_method = self.get_settings( - "OIDC_PKCE_CODE_CHALLENGE_METHOD", "S256" - ) - code_challenge = generate_code_challenge( - code_verifier, code_challenge_method - ) - - # Append code_challenge to authentication request parameters - params.update( - { - "code_challenge": code_challenge, - "code_challenge_method": code_challenge_method, - } - ) - - else: - code_verifier = None - - add_state_and_verifier_and_nonce_to_session( - request, state, params, code_verifier - ) - + redirect_field_name = get_setting("OIDC_REDIRECT_FIELD_NAME", "next") request.session["oidc_login_next"] = get_next_url(request, redirect_field_name) - - query = urlencode(params) - redirect_url = "{url}?{query}".format( - url=self.OIDC_OP_AUTH_ENDPOINT, query=query - ) + redirect_url = get_url_for_authorization_code_request(request) return HttpResponseRedirect(redirect_url) - def get_extra_params(self, request): - return self.get_settings("OIDC_AUTH_REQUEST_EXTRA_PARAMS", {}) - class OIDCLogoutView(View): """Logout helper view""" http_method_names = ["get", "post"] - @staticmethod - def get_settings(attr, *args): - return import_from_settings(attr, *args) - @property def redirect_url(self): """Return the logout url defined in settings.""" - return self.get_settings("LOGOUT_REDIRECT_URL", "/") + return get_setting("LOGOUT_REDIRECT_URL", "/") def post(self, request): """Log out the user.""" @@ -260,7 +178,7 @@ def post(self, request): if request.user.is_authenticated: # Check if a method exists to build the URL to log out the user # from the OP. - logout_from_op = self.get_settings("OIDC_OP_LOGOUT_URL_METHOD", "") + logout_from_op = get_setting("OIDC_OP_LOGOUT_URL_METHOD", "") if logout_from_op: logout_url = import_string(logout_from_op)(request) @@ -271,6 +189,6 @@ def post(self, request): def get(self, request): """Log out the user.""" - if self.get_settings("ALLOW_LOGOUT_GET_METHOD", False): + if get_setting("ALLOW_LOGOUT_GET_METHOD", False): return self.post(request) return HttpResponseNotAllowed(["POST"]) diff --git a/tests/test_auth.py b/tests/test_auth.py index 5bdda157..d97463f6 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1172,19 +1172,19 @@ def test_retrieve_not_existing_jwk(self, mock_requests): class TestVerifyClaim(TestCase): - @patch("mozilla_django_oidc.auth.import_from_settings") + @patch("mozilla_django_oidc.auth.get_setting") def test_returns_false_if_email_not_in_claims(self, patch_settings): patch_settings.return_value = "openid email" ret = OIDCAuthenticationBackend().verify_claims({}) self.assertFalse(ret) - @patch("mozilla_django_oidc.auth.import_from_settings") + @patch("mozilla_django_oidc.auth.get_setting") def test_returns_true_if_email_in_claims(self, patch_settings): patch_settings.return_value = "openid email" ret = OIDCAuthenticationBackend().verify_claims({"email": "email@example.com"}) self.assertTrue(ret) - @patch("mozilla_django_oidc.auth.import_from_settings") + @patch("mozilla_django_oidc.auth.get_setting") @patch("mozilla_django_oidc.auth.LOGGER") def test_returns_true_custom_claims(self, patch_logger, patch_settings): patch_settings.return_value = "foo bar" diff --git a/tests/test_utils.py b/tests/test_utils.py index 5a4a740b..06c6bd8a 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -10,22 +10,22 @@ base64_url_decode, base64_url_encode, generate_code_challenge, - import_from_settings, + get_setting, ) class SettingImportTestCase(TestCase): @override_settings(EXAMPLE_VARIABLE="example_value") def test_attr_existing_no_default_value(self): - s = import_from_settings("EXAMPLE_VARIABLE") + s = get_setting("EXAMPLE_VARIABLE") self.assertEqual(s, "example_value") def test_attr_nonexisting_no_default_value(self): with self.assertRaises(ImproperlyConfigured): - import_from_settings("EXAMPLE_VARIABLE") + get_setting("EXAMPLE_VARIABLE") def test_attr_nonexisting_default_value(self): - s = import_from_settings("EXAMPLE_VARIABLE", "example_default") + s = get_setting("EXAMPLE_VARIABLE", "example_default") self.assertEqual(s, "example_default") @@ -159,7 +159,7 @@ def test_multiple_states(self): self.assertIn(state2, self.request.session["oidc_states"].keys()) def test_max_states(self): - limit = import_from_settings("OIDC_MAX_STATES", 50) + limit = get_setting("OIDC_MAX_STATES", 50) first_state = "example_state_0" params = {}