0001-idp_oidc-revoke-oidc-claims-authorization-45200.patch
src/authentic2/templates/authentic2/authorized_oauth_apps.html | ||
---|---|---|
1 |
{% extends "authentic2/base-page.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block content %} |
|
5 |
{% block oidc-authorized-oauth-apps-pre %}{% endblock %} |
|
6 |
<div id="oidc-authorized-oauth-apps" class="authorized-oauth-apps"> |
|
7 |
{% block oidc-authorized-oauth-apps-top %}{% endblock %} |
|
8 |
{% if authorized_oauth_apps|length_is:0 %} |
|
9 |
{% trans "You have no granted application access to your account." %} |
|
10 |
{% else %} |
|
11 |
<ul> |
|
12 |
{% for auth in authorized_oauth_apps %} |
|
13 |
<li> |
|
14 |
<form method="post"> |
|
15 |
{% csrf_token %} |
|
16 |
<input type="hidden" id="auth-id" name="auth_id" value="{{ auth.id }}"> |
|
17 |
<span class="oidc-authorized-oauth-apps-client"> |
|
18 |
{{ auth.client }} |
|
19 |
</span> |
|
20 |
<span class="oidc-authorized-oauth-apps-since"> |
|
21 |
allowed since {{ auth.created }} |
|
22 |
</span> |
|
23 |
<span class="oidc-authorized-oauth-apps-expired"> |
|
24 |
(expire on {{ auth.expired }}) |
|
25 |
</span> |
|
26 |
<button class="delete-button">{% trans 'Delete' %}</button> |
|
27 |
</form> |
|
28 |
</li> |
|
29 |
{% endfor %} |
|
30 |
</ul> |
|
31 |
</table> |
|
32 |
{% endif %} |
|
33 |
{% block oidc-authorized-oauth-apps-bottom %}{% endblock %} |
|
34 |
</div> |
|
35 |
{% block oidc-authorized-oauth-apps-post %}{% endblock %} |
|
36 |
{% endblock %} |
src/authentic2/urls.py | ||
---|---|---|
64 | 64 |
views.edit_profile, |
65 | 65 |
name='profile_edit_with_scope'), |
66 | 66 |
url(r'^change-email/$', |
67 | 67 |
views.email_change, |
68 | 68 |
name='email-change'), |
69 | 69 |
url(r'^change-email/verify/$', |
70 | 70 |
views.email_change_verify, |
71 | 71 |
name='email-change-verify'), |
72 |
url(r'^authorizations/$', |
|
73 |
login_required(views.authorized_oauth_apps), |
|
74 |
name='authorized-oauth-apps'), |
|
72 | 75 |
url(r'^$', |
73 | 76 |
views.profile, |
74 | 77 |
name='account_management'), |
75 | 78 | |
76 | 79 |
# Password change |
77 | 80 |
url(r'^password/change/$', |
78 | 81 |
views.password_change, |
79 | 82 |
name='password_change'), |
src/authentic2/views.py | ||
---|---|---|
50 | 50 |
from django.http import Http404 |
51 | 51 |
from django.utils.http import urlsafe_base64_decode |
52 | 52 |
from django.views.generic.edit import CreateView |
53 | 53 |
from django.forms import CharField |
54 | 54 |
from django.http import HttpResponseBadRequest |
55 | 55 |
from django.template import loader |
56 | 56 | |
57 | 57 |
from authentic2.compat.misc import default_token_generator |
58 |
from authentic2_idp_oidc.models import OIDCAuthorization |
|
58 | 59 |
from . import (utils, app_settings, decorators, constants, |
59 | 60 |
models, cbv, hooks, validators) |
60 | 61 |
from .utils import switch_user |
61 | 62 |
from .a2_rbac.utils import get_default_ou |
62 | 63 |
from .a2_rbac.models import OrganizationalUnit as OU |
63 | 64 |
from .forms import ( |
64 | 65 |
passwords as passwords_forms, |
65 | 66 |
registration as registration_forms, |
... | ... | |
1264 | 1265 |
class SuView(View): |
1265 | 1266 |
def get(self, request, uuid): |
1266 | 1267 |
user = switch_user.resolve_token(uuid) |
1267 | 1268 |
if not user: |
1268 | 1269 |
raise Http404 |
1269 | 1270 |
return utils.simulate_authentication(request, user, 'su') |
1270 | 1271 | |
1271 | 1272 |
su = SuView.as_view() |
1273 | ||
1274 | ||
1275 |
class AuthorizedOauthAppsView(TemplateView): |
|
1276 |
template_name = 'authentic2/authorized_oauth_apps.html' |
|
1277 |
title = _('Granted Applications') |
|
1278 | ||
1279 |
def get_context_data(self, **kwargs): |
|
1280 |
context = super(AuthorizedOauthAppsView, self).get_context_data(**kwargs) |
|
1281 |
context['authorized_oauth_apps'] = OIDCAuthorization.objects.filter( |
|
1282 |
user=self.request.user) |
|
1283 |
return context |
|
1284 | ||
1285 |
def post(self, request, *args, **kwargs): |
|
1286 |
if request.user: |
|
1287 |
qs = OIDCAuthorization.objects.filter(user=request.user) |
|
1288 |
auth_id = request.POST.get('auth_id') |
|
1289 |
if auth_id: |
|
1290 |
qs = qs.filter(id=auth_id) |
|
1291 |
qs.delete() |
|
1292 |
return HttpResponseRedirect(reverse('authorized-oauth-apps')) |
|
1293 | ||
1294 | ||
1295 |
authorized_oauth_apps = AuthorizedOauthAppsView.as_view() |
tests/test_idp_oidc.py | ||
---|---|---|
1599 | 1599 |
with pytest.raises(ValidationError, match=r'same domain'): |
1600 | 1600 |
OIDCClient( |
1601 | 1601 |
redirect_uris='https://example.com/ https://example2.com/', |
1602 | 1602 |
identifier_policy=OIDCClient.POLICY_PAIRWISE).clean() |
1603 | 1603 | |
1604 | 1604 |
OIDCClient( |
1605 | 1605 |
redirect_uris='https://example.com/ https://example2.com/', |
1606 | 1606 |
sector_identifier_uri='https://example.com/').clean() |
1607 | ||
1608 | ||
1609 |
def test_oidc_authorized_oauth_apps_views(app, oidc_client, simple_user): |
|
1610 |
url = make_url('authorized-oauth-apps') |
|
1611 |
response = app.get(url, status=302) |
|
1612 |
assert '/login/' in response.location |
|
1613 | ||
1614 |
utils.login(app, simple_user) |
|
1615 |
response = app.get(url, status=200) |
|
1616 |
assert "You have no granted application access to your account." in response.text |
|
1617 | ||
1618 |
OIDCAuthorization.objects.create( |
|
1619 |
client=oidc_client, user=simple_user, scopes='openid', |
|
1620 |
expired=now() + datetime.timedelta(days=2)) |
|
1621 |
OIDCAuthorization.objects.create( |
|
1622 |
client=oidc_client, user=simple_user, scopes='openid profile', |
|
1623 |
expired=now() + datetime.timedelta(days=2)) |
|
1624 |
OIDCAuthorization.objects.create( |
|
1625 |
client=oidc_client, user=simple_user, scopes='openid profile email', |
|
1626 |
expired=now() + datetime.timedelta(days=2)) |
|
1627 | ||
1628 |
response = app.get(url, status=200) |
|
1629 |
assert "You have no granted application access to your account." not in response.text |
|
1630 |
assert len(response.html.find_all('button', {'class': 'delete-button'})) == 3 |
|
1631 | ||
1632 |
# revoke one |
|
1633 |
response = response.forms[1].submit() |
|
1634 |
response = response.follow() |
|
1635 |
assert len(response.html.find_all('button', {'class': 'delete-button'})) == 2 |
|
1607 |
- |