def process_request(self, request): if request.method != 'GET': return try: resolve(request.path_info) except Resolver404: return self.now = timezone.now() self.url = reverse('password_change') if settings.PASSWORD_DURATION_SECONDS and \ request.user.is_authenticated() and \ not self._is_excluded_path(request.path): self.check = PasswordCheck(request.user) self.expiry_datetime = self.check.get_expiry_datetime() self._check_necessary(request) return self._redirect(request)
def process_request(self, request): if request.method != 'GET': return try: resolve(request.path_info) except Resolver404: return self.now = timezone.now() self.url = reverse('password_change') try: # Did this ever worked? It gives error on Django 2.0 # and I haven't ran the test suite before that... auth = request.user.is_authenticated() except TypeError: auth = request.user.is_authenticated if settings.PASSWORD_DURATION_SECONDS and \ auth and not self._is_excluded_path(request.path): self.check = PasswordCheck(request.user) self.expiry_datetime = self.check.get_expiry_datetime() self._check_necessary(request) return self._redirect(request)
class PasswordPoliciesUtilsTest(TestCase): def setUp(self): self.user = create_user() self.check = PasswordCheck(self.user) create_password_history(self.user) return super(PasswordPoliciesUtilsTest, self).setUp() def test_password_check_is_required(self): # by default no change is required self.assertFalse(self.check.is_required()) # until a change is required (usually by middleware) PasswordChangeRequired.objects.create(user=self.user) self.assertTrue(self.check.is_required()) def test_password_check_is_expired(self): # `create_password_history` creates a history starting at # t - PASSWORD_DURATION_SECONDS, so the password is expired self.assertTrue(self.check.is_expired()) # now we create a password now, so it isn't expired PasswordHistory.objects.create(user=self.user, password="******") self.assertFalse(self.check.is_expired())
class PasswordPoliciesUtilsTest(BaseTest): def setUp(self): self.user = create_user() self.check = PasswordCheck(self.user) create_password_history(self.user) return super(PasswordPoliciesUtilsTest, self).setUp() def test_password_check_is_required(self): # by default no change is required self.assertFalse(self.check.is_required()) # until a change is required (usually by middleware) PasswordChangeRequired.objects.create(user=self.user) self.assertTrue(self.check.is_required()) def test_password_check_is_expired(self): # `create_password_history` creates a history starting at # t - PASSWORD_DURATION_SECONDS, so the password is expired self.assertTrue(self.check.is_expired()) # now we create a password now, so it isn't expired PasswordHistory.objects.create(user=self.user, password='******') self.assertFalse(self.check.is_expired())
class PasswordChangeMiddleware(MiddlewareMixin): """ A middleware to force a password change. If a password history exists the last change of password can easily be determined by just getting the newest entry. If the user has no password history it is assumed that the password was last changed when the user has or was registered. .. note:: This only works on a GET HTTP method. Redirections on a HTTP POST are tricky, so the risk of messing up a POST is not taken... To use this middleware you need to add it to the ``MIDDLEWARE_CLASSES`` list in a project's settings:: MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'password_policies.middleware.PasswordChangeMiddleware', # ... other middleware ... ) or ``MIDDLEWARE`` if using Django 1.10 or higher: MIDDLEWARE = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'password_policies.middleware.PasswordChangeMiddleware', # ... other middleware ... ) .. note:: The order of this middleware in the stack is important, it must be listed after the authentication AND the session middlewares. .. warning:: This middleware does not try to redirect using the HTTPS protocol. """ checked = '_password_policies_last_checked' expired = '_password_policies_expired' last = '_password_policies_last_changed' required = '_password_policies_change_required' td = timedelta(seconds=settings.PASSWORD_DURATION_SECONDS) def _check_history(self, request): if not request.session.get(self.last, None): newest = PasswordHistory.objects.get_newest(request.user) if newest: request.session[self.last] = DateSerializer.serialize( newest.created) else: # TODO: This relies on request.user.date_joined which might not # be available!!! request.session[self.last] = DateSerializer.serialize( request.user.date_joined) if DateSerializer.deserialize(request.session[self.last]).replace( tzinfo=None) < self.expiry_datetime.replace(tzinfo=None): request.session[self.required] = True if not PasswordChangeRequired.objects.filter( user=request.user).count(): PasswordChangeRequired.objects.create(user=request.user) else: request.session[self.required] = False def _check_necessary(self, request): if not request.session.get(self.checked, None): request.session[self.checked] = DateSerializer.serialize(self.now) # If the PASSWORD_CHECK_ONLY_AT_LOGIN is set, then only check at the beginning of session, which we can # tell by self.now time having just been set. if not settings.PASSWORD_CHECK_ONLY_AT_LOGIN or request.session.get( self.checked, None) == DateSerializer.serialize(self.now): # If a password change is enforced we won't check # the user's password history, thus reducing DB hits... if PasswordChangeRequired.objects.filter( user=request.user).count(): request.session[self.required] = True return if DateSerializer.deserialize( request.session[self.checked]).replace( tzinfo=None) < self.expiry_datetime.replace( tzinfo=None): try: del request.session[self.last] del request.session[self.checked] del request.session[self.required] del request.session[self.expired] except KeyError: pass if settings.PASSWORD_USE_HISTORY: self._check_history(request) else: # In the case where PASSWORD_CHECK_ONLY_AT_LOGIN is true, the required key is not removed, # therefore causing a never ending password update loop request.session[self.required] = False def _is_excluded_path(self, actual_path): paths = settings.PASSWORD_CHANGE_MIDDLEWARE_EXCLUDED_PATHS[:] path = r'^%s$' % self.url paths.append(path) media_url = settings.MEDIA_URL if media_url: paths.append(r'^%s?' % media_url) static_url = settings.STATIC_URL if static_url: paths.append(r'^%s?' % static_url) if settings.PASSWORD_CHANGE_MIDDLEWARE_ALLOW_LOGOUT: try: logout_url = reverse('home:logout') except NoReverseMatch: pass else: paths.append(r'^%s$' % logout_url) try: logout_url = u'/admin/logout/' resolve(logout_url) except Resolver404: pass else: paths.append(r'^%s$' % logout_url) for path in paths: if re.match(path, actual_path): return True return False def _redirect(self, request): if request.session[self.required]: redirect_to = request.GET.get(settings.REDIRECT_FIELD_NAME, '') if redirect_to: next_to = redirect_to else: next_to = request.get_full_path() url = "%s?%s=%s" % (self.url, settings.REDIRECT_FIELD_NAME, next_to) return HttpResponseRedirect(url) def process_request(self, request): if request.method != 'GET': return try: resolve(request.path_info) except Resolver404: return self.now = timezone.now() self.url = reverse('password_change') try: # Did this ever worked? It gives error on Django 2.0 # and I haven't ran the test suite before that... auth = request.user.is_authenticated() except TypeError: auth = request.user.is_authenticated if settings.PASSWORD_DURATION_SECONDS and \ auth and not self._is_excluded_path(request.path): self.check = PasswordCheck(request.user) self.expiry_datetime = self.check.get_expiry_datetime() self._check_necessary(request) return self._redirect(request)
def setUp(self): self.user = create_user() self.check = PasswordCheck(self.user) create_password_history(self.user) return super(PasswordPoliciesUtilsTest, self).setUp()
class PasswordChangeMiddleware(object): """ A middleware to force a password change. If a password history exists the last change of password can easily be determined by just getting the newest entry. If the user has no password history it is assumed that the password was last changed when the user has or was registered. .. note:: This only works on a GET HTTP method. Redirections on a HTTP POST are tricky, so the risk of messing up a POST is not taken... To use this middleware you need to add it to the ``MIDDLEWARE_CLASSES`` list in a project's settings:: MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'password_policies.middleware.PasswordChangeMiddleware', # ... other middlewares ... ) .. note:: The order of this middleware in the stack is important, it must be listed after the authentication AND the session middlewares. .. warning:: This middleware does not try to redirect using the HTTPS protocol. """ checked = '_password_policies_last_checked' expired = '_password_policies_expired' last = '_password_policies_last_changed' required = '_password_policies_change_required' td = timedelta(seconds=settings.PASSWORD_DURATION_SECONDS) def _check_history(self, request): if not request.session.get(self.last, None): newest = PasswordHistory.objects.get_newest(request.user) if newest: request.session[self.last] = json.dumps(newest.created,cls=DateTimeEncoder) else: # TODO: This relies on request.user.date_joined which might not # be available!!! request.session[self.last] = json.dumps(request.user.date_joined,cls=DateTimeEncoder) last = json.loads(request.session[self.last], cls=DateTimeDecoder) if last < self.expiry_datetime: request.session[self.required] = True if not PasswordChangeRequired.objects.filter(user=request.user).count(): PasswordChangeRequired.objects.create(user=request.user) else: request.session[self.required] = False def _check_necessary(self, request): if not request.session.get(self.checked, None): request.session[self.checked] = json.dumps(self.now,cls=DateTimeEncoder) last_check = json.loads(request.session.get(self.checked, None), cls=DateTimeDecoder) # If the PASSWORD_CHECK_ONLY_AT_LOGIN is set, then only check at the beginning of session, which we can # tell by self.now time having just been set. if not settings.PASSWORD_CHECK_ONLY_AT_LOGIN or last_check == self.now: # If a password change is enforced we won't check # the user's password history, thus reducing DB hits... if PasswordChangeRequired.objects.filter(user=request.user).count(): request.session[self.required] = True return if last_check < self.expiry_datetime: try: del request.session[self.last] del request.session[self.checked] del request.session[self.required] del request.session[self.expired] except KeyError: pass if settings.PASSWORD_USE_HISTORY: self._check_history(request) else: # In the case where PASSWORD_CHECK_ONLY_AT_LOGIN is true, the required key is not removed, # therefore causing a never ending password update loop request.session[self.required] = False def _is_excluded_path(self, actual_path): paths = settings.PASSWORD_CHANGE_MIDDLEWARE_EXCLUDED_PATHS path = r'^%s$' % self.url paths.append(path) media_url = settings.MEDIA_URL if media_url: paths.append(r'^%s?' % media_url) static_url = settings.STATIC_URL if static_url: paths.append(r'^%s?' % static_url) if settings.PASSWORD_CHANGE_MIDDLEWARE_ALLOW_LOGOUT: try: logout_url = reverse('logout') except NoReverseMatch: pass else: paths.append(r'^%s$' % logout_url) try: logout_url = u'/admin/logout/' resolve(logout_url) except Resolver404: pass else: paths.append(r'^%s$' % logout_url) for path in paths: if re.match(path, actual_path): return True return False def _redirect(self, request): if request.session[self.required]: redirect_to = request.GET.get(settings.REDIRECT_FIELD_NAME, '') if redirect_to: next_to = redirect_to else: next_to = request.get_full_path() url = "%s?%s=%s" % (self.url, settings.REDIRECT_FIELD_NAME, next_to) return HttpResponseRedirect(url) def process_request(self, request): if request.method != 'GET': return try: resolve(request.path_info) except Resolver404: return self.now = timezone.now() self.url = reverse('password_change') if settings.PASSWORD_DURATION_SECONDS and \ request.user.is_authenticated() and \ not self._is_excluded_path(request.path): self.check = PasswordCheck(request.user) self.expiry_datetime = self.check.get_expiry_datetime() self._check_necessary(request) return self._redirect(request)