2525from django .contrib .auth .models import User
2626from django .conf import settings
2727from django .template .loader import render_to_string
28+ from django .test .utils import override_settings
2829from django .utils import timezone
2930
3031import debug # pyflakes:ignore
4243from ietf .utils .mail import outbox , empty_outbox , get_payload_text
4344from ietf .utils .test_utils import TestCase , login_testing_unauthorized
4445from ietf .utils .timezone import date_today
46+ from ..settings import PASSWORD_POLICY_MAX_LOGIN_AGE
4547
4648
4749class IetfAuthTests (TestCase ):
@@ -115,6 +117,46 @@ def test_login_with_different_email(self):
115117 self .assertEqual (r .status_code , 302 )
116118 self .assertEqual (urlsplit (r ["Location" ])[2 ], urlreverse ("ietf.ietfauth.views.profile" ))
117119
120+ def test_login_with_stale_account (self ):
121+ VALID_PASSWORD = "complex-and-long-valid-password"
122+ LONG_TIME = datetime .timedelta (days = 730 )
123+ now = datetime .datetime .now (datetime .timezone .utc )
124+ login_url = urlreverse ("ietf.ietfauth.views.login" )
125+ success_url = urlreverse ("ietf.ietfauth.views.profile" ) # redirect target
126+ user = PersonFactory (user__username = "stale@example.com" ).user
127+ user .set_password (VALID_PASSWORD )
128+ user .save ()
129+ login_data = {
130+ "username" : user .username ,
131+ "password" : VALID_PASSWORD ,
132+ }
133+
134+ # newly-created user (no last_login, recent date_joined)
135+ with override_settings (PASSWORD_POLICY_MAX_LOGIN_AGE = LONG_TIME ):
136+ r = self .client .post (login_url , login_data )
137+ self .assertEqual (r .status_code , 302 )
138+ self .assertEqual (urlsplit (r ["Location" ])[2 ], success_url )
139+
140+ # just barely recent enough
141+ user .date_joined = now - 2 * LONG_TIME # joined long, long ago...
142+ user .last_login = now - LONG_TIME + datetime .timedelta (days = 1 )
143+ user .save ()
144+ with override_settings (PASSWORD_POLICY_MAX_LOGIN_AGE = LONG_TIME ):
145+ r = self .client .post (login_url , login_data )
146+ self .assertEqual (r .status_code , 302 )
147+ self .assertEqual (urlsplit (r ["Location" ])[2 ], success_url )
148+
149+ # too long ago
150+ user .last_login = now - LONG_TIME - datetime .timedelta (days = 1 )
151+ user .save ()
152+ with override_settings (PASSWORD_POLICY_MAX_LOGIN_AGE = LONG_TIME ):
153+ r = self .client .post (login_url , login_data )
154+ self .assertContains (
155+ r ,
156+ "too long since your last login" ,
157+ status_code = 200 ,
158+ )
159+
118160 def extract_confirm_url (self , confirm_email ):
119161 # dig out confirm_email link
120162 msg = get_payload_text (confirm_email )
@@ -127,8 +169,7 @@ def extract_confirm_url(self, confirm_email):
127169
128170 return confirm_url
129171
130-
131- # For the lowered barrier to account creation period, we are disabling this kind of failure
172+ # For the lowered barrier to account creation period, we are disabling this kind of failure
132173 # def test_create_account_failure(self):
133174
134175 # url = urlreverse("ietf.ietfauth.views.create_account")
@@ -144,7 +185,7 @@ def extract_confirm_url(self, confirm_email):
144185 # self.assertEqual(r.status_code, 200)
145186 # self.assertContains(r, "Additional Assistance Required")
146187
147- # Rather than delete the failure template just yet, here's a test to make sure it still renders should we need to revert to it.
188+ # Rather than delete the failure template just yet, here's a test to make sure it still renders should we need to revert to it.
148189 def test_create_account_failure_template (self ):
149190 r = render_to_string ('registration/manual.html' , { 'account_request_email' : settings .ACCOUNT_REQUEST_EMAIL })
150191 self .assertTrue ("Additional Assistance Required" in r )
@@ -179,7 +220,6 @@ def register_and_verify(self, email):
179220 self .assertEqual (Person .objects .filter (user__username = email ).count (), 1 )
180221 self .assertEqual (Email .objects .filter (person__user__username = email ).count (), 1 )
181222
182-
183223 # This also tests new account creation.
184224 def test_create_existing_account (self ):
185225 # create account once
@@ -205,7 +245,6 @@ def test_ietfauth_profile(self):
205245 url = urlreverse ("ietf.ietfauth.views.profile" )
206246 login_testing_unauthorized (self , username , url )
207247
208-
209248 # get
210249 r = self .client .get (url )
211250 self .assertEqual (r .status_code , 200 )
@@ -325,7 +364,6 @@ def test_ietfauth_profile(self):
325364 q = PyQuery (r .content )
326365 self .assertTrue (len (q ("form div.invalid-feedback" )) == 1 )
327366
328-
329367 # change role email
330368 role = Role .objects .create (
331369 person = Person .objects .get (user__username = username ),
@@ -340,7 +378,7 @@ def test_ietfauth_profile(self):
340378 self .assertEqual (r .status_code , 200 )
341379 q = PyQuery (r .content )
342380 self .assertEqual (len (q ('[name="%s"]' % role_email_input_name )), 1 )
343-
381+
344382 with_changed_role_email = base_data .copy ()
345383 with_changed_role_email ["active_emails" ] = new_email_address
346384 with_changed_role_email [role_email_input_name ] = new_email_address
@@ -767,7 +805,7 @@ def test_apikey_management(self):
767805 for endpoint , display in endpoints :
768806 r = self .client .post (url , {'endpoint' : endpoint })
769807 self .assertRedirects (r , urlreverse ('ietf.ietfauth.views.apikey_index' ))
770-
808+
771809 # Check api key list content
772810 url = urlreverse ('ietf.ietfauth.views.apikey_index' )
773811 r = self .client .get (url )
@@ -798,7 +836,7 @@ def test_apikey_management(self):
798836 r = self .client .post (url , {'hash' : otherkey .hash ()})
799837 self .assertEqual (r .status_code , 200 )
800838 self .assertContains (r ,"Key validation failed; key not disabled" )
801-
839+
802840 # Delete a key
803841 r = self .client .post (url , {'hash' : key .hash ()})
804842 self .assertRedirects (r , urlreverse ('ietf.ietfauth.views.apikey_index' ))
@@ -885,7 +923,7 @@ def test_send_apikey_report(self):
885923 for endpoint , display in endpoints :
886924 r = self .client .post (url , {'endpoint' : endpoint })
887925 self .assertRedirects (r , urlreverse ('ietf.ietfauth.views.apikey_index' ))
888-
926+
889927 # Use the endpoints (the form content will not be acceptable, but the
890928 # apikey usage will be registered)
891929 count = 2
0 commit comments