apps: hide password management link when FC authenticated (#27083)

It's done by implementing a2_hook_user_can_change_password on the
AppConfig object.
This commit is contained in:
Benjamin Dauvergne 2019-05-03 10:11:47 +02:00
parent 1f7b1c6a58
commit ce56e15d0b
2 changed files with 111 additions and 0 deletions

View File

@ -1,6 +1,8 @@
from . import utils
from . import app_settings
from authentic2.utils import get_authentication_events
import django.apps
@ -71,5 +73,11 @@ class AppConfig(django.apps.AppConfig):
return True
return None
def a2_hook_user_can_change_password(self, user, request, **kwargs):
for authentication_event in get_authentication_events(request=request):
if authentication_event['how'] == 'france-connect':
return False
return True
default_app_config = '%s.%s' % (__name__, 'AppConfig')

View File

@ -456,3 +456,106 @@ def test_registration2(app, fc_settings, caplog, hooks):
assert app.session['fc_states'][state]['next'] == '/accounts/'
response = app.get(reverse('fc-logout') + '?state=' + state)
assert path(response['Location']) == '/accounts/'
def test_can_change_password(app, fc_settings, caplog, hooks):
exp = timestamp_from_datetime(now() + datetime.timedelta(seconds=1000))
response = app.get('/login/?service=portail&next=/idp/')
response = response.click("Register")
response = response.click(href='callback')
# 1. Try a login
# 2. Verify we come back to login page
# 3. Check presence of registration link
# 4. Follow it
location = response['Location']
state = check_authorization_url(location)
@httmock.urlmatch(path=r'.*/token$')
def access_token_response(url, request):
parsed = {x: y[0] for x, y in urlparse.parse_qs(request.body).items()}
assert set(parsed.keys()) == set(['code', 'client_id', 'client_secret', 'redirect_uri',
'grant_type'])
assert parsed['code'] == 'zzz'
assert parsed['client_id'] == 'xxx'
assert parsed['client_secret'] == 'yyy'
assert parsed['grant_type'] == 'authorization_code'
assert callback in parsed['redirect_uri']
id_token = {
'sub': '1234',
'aud': 'xxx',
'nonce': state,
'exp': exp,
'iss': 'https://fcp.integ01.dev-franceconnect.fr/',
'email': 'john.doe@example.com',
}
return json.dumps({
'access_token': 'uuu',
'id_token': hmac_jwt(id_token, 'yyy')
})
@httmock.urlmatch(path=r'.*userinfo$')
def user_info_response(url, request):
assert request.headers['Authorization'] == 'Bearer uuu'
return json.dumps({
'sub': '1234',
'family_name': u'Frédérique',
'given_name': u'Ÿuñe',
'email': 'john.doe@example.com',
})
callback = urlparse.parse_qs(urlparse.urlparse(location).query)['redirect_uri'][0]
with httmock.HTTMock(access_token_response, user_info_response):
response = app.get(callback + '&code=zzz&state=%s' % state, status=302)
assert User.objects.count() == 0
assert path(response['Location']) == '/accounts/fc/register/'
response = response.follow()
location = response['Location']
location.startswith('http://testserver/accounts/activate/')
response = response.follow()
assert hooks.calls['event'][0]['kwargs']['service'] == 'portail'
assert hooks.calls['event'][1]['kwargs']['service'] == 'portail'
# we must be connected
assert app.session['_auth_user_id']
# remove the registration parameter
callback = callback.replace('&registration=', '')
callback = callback.replace('?registration=', '?')
callback = callback.replace('?&', '?')
assert path_and_query(response['Location']) == path_and_query(callback)
response = response.follow()
location = response['Location']
state = check_authorization_url(location)
with httmock.HTTMock(access_token_response, user_info_response):
response = app.get(callback + '&code=zzz&state=%s' % state, status=302)
assert models.FcAccount.objects.count() == 1
user = User.objects.get()
assert user.verified_attributes.first_name == u'Ÿuñe'
assert user.verified_attributes.last_name == u'Frédérique'
response = app.get('/accounts/')
assert len(response.pyquery('[href*="password/change"]')) == 0
# Login with password
user = User.objects.get()
user.set_password('test')
user.save()
app.session.flush()
response = app.get('/login/')
response.form.set('username', User.objects.get().email)
response.form.set('password', 'test')
response = response.form.submit(name='login-password-submit').follow()
response = app.get('/accounts/')
assert len(response.pyquery('[href*="password/change"]')) > 0
# Relogin with FC
app.session.flush()
response = app.get('/login/?service=portail&next=/accounts/')
response = response.click(href='callback')
location = response['Location']
state = check_authorization_url(location)
callback = urlparse.parse_qs(urlparse.urlparse(location).query)['redirect_uri'][0]
with httmock.HTTMock(access_token_response, user_info_response):
response = app.get(callback + '&code=zzz&state=%s' % state, status=302)
# we must be connected
assert app.session['_auth_user_id']
assert path(response['Location']) == '/accounts/'
response = response.follow()
assert len(response.pyquery('[href*="password/change"]')) == 0