idp_oidc: add "do not ask again" authorization checkbox (#39552)

This commit is contained in:
Benjamin Dauvergne 2020-01-29 21:32:02 +01:00
parent 85fdc938c9
commit ee8b54d383
3 changed files with 37 additions and 26 deletions

View File

@ -1,7 +1,7 @@
{% extends "authentic2/base-page.html" %}
{% load i18n %}
{% block content %}
<form method="post" id="a2-oidc-authorization-form">
<form method="post" id="a2-oidc-authorization-form">
<p>{% blocktrans with client_name=client.name %}Do you want to be authenticated on service {{ client_name }} ?{% endblocktrans %}</p>
{% if scopes %}
<p>{% trans "The following informations will be sent to the service:" %}</p>
@ -16,6 +16,9 @@
</ul>
{% endif %}
{% csrf_token %}
<p class="a2-oidc-authorization-form--do-not-ask-again">
<label for="id_do_not_ask_again"><input type="checkbox" name="do_not_ask_again" value="on"/><span>{% trans "Do not ask again" %}</span></label>
</p>
<button name="accept">{% trans "Accept" %}</button>
<button name="refuse">{% trans "Refuse" %}</button>
</form>

View File

@ -271,18 +271,22 @@ def authorize(request, *args, **kwargs):
fragment=fragment)
if request.method == 'POST':
if 'accept' in request.POST:
pk_to_deletes = []
for authorization in qs:
# clean obsolete authorizations
if authorization.scope_set() <= scopes:
pk_to_deletes.append(authorization.pk)
auth_manager.create(
user=request.user, scopes=u' '.join(sorted(scopes)),
expired=start + datetime.timedelta(days=365))
if pk_to_deletes:
auth_manager.filter(pk__in=pk_to_deletes).delete()
logger.info(u'authorized scopes %s for service %s', ' '.join(scopes),
client.name)
if 'do_not_ask_again' in request.POST:
pk_to_deletes = []
for authorization in qs:
# clean obsolete authorizations
if authorization.scope_set() <= scopes:
pk_to_deletes.append(authorization.pk)
auth_manager.create(
user=request.user, scopes=u' '.join(sorted(scopes)),
expired=start + datetime.timedelta(days=365))
if pk_to_deletes:
auth_manager.filter(pk__in=pk_to_deletes).delete()
logger.info(u'authorized scopes %s saved for service %s', ' '.join(scopes),
client.name)
else:
logger.info(u'authorized scopes %s for service %s', ' '.join(scopes),
client.name)
else:
logger.info(u'refused scopes %s for service %s', ' '.join(scopes),
client.name)

View File

@ -32,23 +32,20 @@ from django.db import connection
from django.db.migrations.executor import MigrationExecutor
from django.utils.encoding import force_text
from django.utils.timezone import now
from django.test.client import RequestFactory
from django.contrib.auth import get_user_model
from django.utils.six.moves.urllib import parse as urlparse
from ratelimit.utils import is_ratelimited
User = get_user_model()
from authentic2.models import Attribute, AuthorizedRole
from authentic2_idp_oidc.models import OIDCClient, OIDCAuthorization, OIDCCode, OIDCAccessToken, OIDCClaim
from authentic2_idp_oidc.utils import (make_sub, get_first_rsa_sig_key,
base64url)
from authentic2_idp_oidc.utils import make_sub, get_first_rsa_sig_key, base64url
from authentic2.a2_rbac.utils import get_default_ou
from authentic2.utils import make_url
from authentic2_auth_oidc.utils import parse_timestamp
from django_rbac.utils import get_role_model
User = get_user_model()
pytestmark = pytest.mark.django_db
JWKSET = {
@ -176,8 +173,9 @@ def bearer_authentication_headers(access_token):
return {'Authorization': 'Bearer %s' % str(access_token)}
@pytest.mark.parametrize('do_not_ask_again', [(True,), (False,)])
@pytest.mark.parametrize('login_first', [(True,), (False,)])
def test_authorization_code_sso(login_first, oidc_settings, oidc_client, simple_user, app):
def test_authorization_code_sso(login_first, do_not_ask_again, oidc_settings, oidc_client, simple_user, app):
redirect_uri = oidc_client.redirect_uris.split()[0]
params = {
'client_id': oidc_client.client_id,
@ -209,13 +207,17 @@ def test_authorization_code_sso(login_first, oidc_settings, oidc_client, simple_
assert OIDCAuthorization.objects.count() == 0
assert OIDCCode.objects.count() == 0
assert OIDCAccessToken.objects.count() == 0
response.form['do_not_ask_again'] = do_not_ask_again
response = response.form.submit('accept')
assert OIDCAuthorization.objects.count() == 1
authz = OIDCAuthorization.objects.get()
assert authz.client == oidc_client
assert authz.user == simple_user
assert authz.scope_set() == set('openid profile email'.split())
assert authz.expired >= now()
if do_not_ask_again:
assert OIDCAuthorization.objects.count() == 1
authz = OIDCAuthorization.objects.get()
assert authz.client == oidc_client
assert authz.user == simple_user
assert authz.scope_set() == set('openid profile email'.split())
assert authz.expired >= now()
else:
assert OIDCAuthorization.objects.count() == 0
if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
assert OIDCCode.objects.count() == 1
code = OIDCCode.objects.get()
@ -648,6 +650,7 @@ def test_invalid_request(caplog, oidc_settings, oidc_client, simple_user, app):
authorize.scopes = 'openid profile'
authorize.save()
assert OIDCAuthorization.objects.count() == 1
response.form['do_not_ask_again'] = True
response = response.form.submit('accept')
assert OIDCAuthorization.objects.count() == 1
# old authorizations have been deleted
@ -848,6 +851,7 @@ def test_role_control_access(login_first, oidc_settings, oidc_client, simple_use
response = response.form.submit(name='login-password-submit')
response = response.follow()
if oidc_client.authorization_mode != oidc_client.AUTHORIZATION_MODE_NONE:
response.form['do_not_ask_again'] = True
response = response.form.submit('accept')
assert OIDCAuthorization.objects.get()
if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE: