return self.render(request, token=token, rpconfig=rpconfig, form=form)
File "/src/canonical-identity-provider/sso-git/src/webui/views/ui.py", line 128, in render
context = self.get_context(request, **kwargs)
File "/src/canonical-identity-provider/sso-git/src/webui/views/ui.py", line 286, in get_context
if gargoyle.is_active('TWOFACTOR_BACKUP_NAG', request):
File "/src/canonical-identity-provider/sso-git/env/local/lib/python2.7/site-packages/gargoyle/testutils.py", line 125, in wrapped
return is_active_func(key, *args, **kwargs)
File "/src/canonical-identity-provider/sso-git/env/local/lib/python2.7/site-packages/gargoyle/manager.py", line 89, in is_active
result = switch.has_active_condition(conditions, instances)
File "/src/canonical-identity-provider/sso-git/env/local/lib/python2.7/site-packages/gargoyle/conditions.py", line 293, in has_active_condition
result = self.is_active(instance, conditions)
File "/src/canonical-identity-provider/sso-git/env/local/lib/python2.7/site-packages/gargoyle/conditions.py", line 307, in is_active
field_conditions = conditions.get(self.get_namespace(), {}).get(name)
AttributeError: 'unicode' object has no attribute 'get'
THis is apparently because something is fucked in JSONField and it's
returning the data as the verbatim string and not the expected de-jsoned
thing (i.e. it's not running the json payload by json.loads())
fix test that failed with upgraded django-modeldict.
django-modeldict-yplan calls time.time() to get a timestamp to store
modeldict data in Django cache. Prior to 1.5.3 it would int(time.time())
but as of 1.5.3 it stopped doing that and uses time.time() directly.
mocky = mock.MagicMock()
int(mocky) # this is 1, it will be relevant soon.
A bug had been lurking in test_saml_time_conditions since times
immemorial: it was using @patch as a decorator to mock time.time in a
saml2idp (saml2idp.base.time.time), but since it was running time.time()
inside the test method to set up the mock's return value, this resulted
in an inadvertent circular mock:
@patch('saml2idp.base.time.time')
...
now = time.time() # You think this is the system time.time but it's # actually your mock at this point
mock_time.return_value = now # You're making your mock method # return a mock
For some reason, the time.time mocking in saml2idp.base was bleeding
into django-modeldict's update_cache_data method, and since we updated
to version 2.0.3, the rounding behavior explained above which was hiding
the fact that we're passing around a mock instead of a time value
disappeared, exposing a bug where trying to pickle the mocky time in
order to store it in django cache (memcached, here) resulted in
PicklingError: Can't pickle <class 'mock.MagicMock'>: it's not the same object as mock.MagicMock
As seen in the code, the fix was to rearrange scoping so we obtain the
value of time.time() we will set as the mock's return_value *outside* of
the mock's scope.
Periodically nag 2FA users to enter a code from their backup device instead of the primary.
To be clear, a code from the primary or any other device is still accepted.
This is a "soft/gentle" approach to getting people to test their backup device every once in a while *before* they get locked out.
Every X days, a nag message is shown on top of the usual 2FA screen informing users they can enter a backup code and how it helps ensure they are still valid. It also shows the most recent use date for *any* backup device.
The TWOFACTOR_BACKUP_NAG flag controls this behavior, and time between nags is controlled by the "TWOFACTOR_BACKUP_NAG_INTERVAL setting which has a value of 42 days but can be changed.