diff --git a/oauth2_provider/models.py b/oauth2_provider/models.py index ba42086bc..153d81633 100644 --- a/oauth2_provider/models.py +++ b/oauth2_provider/models.py @@ -4,6 +4,7 @@ from django.apps import apps from django.conf import settings +from django.contrib.auth.hashers import identify_hasher, make_password from django.db import models, transaction from django.utils import timezone @@ -137,6 +138,24 @@ def is_usable(self, request): """ return True + def save(self, *args, **kwargs): + if self.client_secret: + # I'ts necessary to check if client_secret was already encrypted + try: + hasher = identify_hasher(self.client_secret) + return super(AbstractApplication, self).save(*args, **kwargs) + except ValueError: + # TODO: remove log below + print("---"*30) + print(" client_secret: {}".format(self.client_secret)) + hashed_secret = make_password(self.client_secret) + # TODO: remove log below + print("---"*30) + print(" hashed_secret: {}".format(hashed_secret)) + self.client_secret = hashed_secret + + return super(AbstractApplication, self).save(*args, **kwargs) + class AppManager(models.Manager): def get_queryset(self): diff --git a/oauth2_provider/oauth2_validators.py b/oauth2_provider/oauth2_validators.py index 5ed033a20..2f06eb12f 100644 --- a/oauth2_provider/oauth2_validators.py +++ b/oauth2_provider/oauth2_validators.py @@ -6,7 +6,9 @@ from datetime import timedelta from django.utils import timezone +from django.utils.crypto import constant_time_compare from django.conf import settings +from django.contrib.auth.hashers import check_password, identify_hasher from django.contrib.auth import authenticate from django.core.exceptions import ObjectDoesNotExist from django.db import transaction @@ -50,6 +52,17 @@ def _extract_basic_auth(self, request): return auth_string + def _check_secret(self, provided_secret, stored_secret): + """ + Checks whether the provided client secret is valid. + Supports both hashed and unhashed secrets. + """ + try: + identify_hasher(stored_secret) + return check_password(provided_secret, stored_secret) + except ValueError: # Raised if the stored_secret is not hashed. + return constant_time_compare(provided_secret, stored_secret) + def _authenticate_basic_auth(self, request): """ Authenticates with HTTP Basic Auth. @@ -88,7 +101,7 @@ def _authenticate_basic_auth(self, request): elif request.client.client_id != client_id: log.debug("Failed basic auth: wrong client id %s" % client_id) return False - elif request.client.client_secret != client_secret: + elif not self._check_secret(client_secret, request.client.client_secret): log.debug("Failed basic auth: wrong client secret %s" % client_secret) return False else: @@ -113,7 +126,7 @@ def _authenticate_request_body(self, request): if self._load_application(client_id, request) is None: log.debug("Failed body auth: Application %s does not exists" % client_id) return False - elif request.client.client_secret != client_secret: + elif not self._check_secret(client_secret, request.client.client_secret): log.debug("Failed body auth: wrong client secret %s" % client_secret) return False else: