0007-misc-use-hooks-to-accumulate-redirect-logout-urls-69.patch
src/authentic2/views.py | ||
---|---|---|
591 | 591 | |
592 | 592 | |
593 | 593 |
def redirect_logout_list(request): |
594 |
'''Return redirect logout links from idp backends''' |
|
595 |
return utils_misc.accumulate_from_backends(request, 'redirect_logout_list') |
|
594 |
'''Return redirect logout URLs from idp backends or authenticators''' |
|
595 |
redirect_logout_list = [] |
|
596 |
for urls in hooks.call_hooks('redirect_logout_list', request=request): |
|
597 |
if urls: |
|
598 |
redirect_logout_list.extend(urls) |
|
599 |
return redirect_logout_list |
|
596 | 600 | |
597 | 601 | |
598 | 602 |
def logout(request, next_url=None, do_local=True, check_referer=True): |
src/authentic2_auth_fc/apps.py | ||
---|---|---|
18 | 18 |
from django import template |
19 | 19 | |
20 | 20 | |
21 |
class Plugin: |
|
22 |
def redirect_logout_list(self, request, **kwargs): |
|
23 |
from django.urls import reverse |
|
24 | ||
25 |
from . import utils |
|
26 |
from .models import FcAuthenticator |
|
27 | ||
28 |
try: |
|
29 |
authenticator = FcAuthenticator.objects.get() |
|
30 |
except FcAuthenticator.DoesNotExist: |
|
31 |
return [] |
|
32 | ||
33 |
url = utils.build_logout_url(request, authenticator.logout_url, next_url=reverse('auth_logout')) |
|
34 |
# url is assumed empty if no active session on the OP. |
|
35 |
if url: |
|
36 |
return [url] |
|
37 |
return [] |
|
38 | ||
39 | ||
40 | 21 |
class AppConfig(django.apps.AppConfig): |
41 | 22 |
name = 'authentic2_auth_fc' |
42 | 23 | |
43 |
def get_a2_plugin(self): |
|
44 |
return Plugin() |
|
45 | ||
46 | 24 |
def a2_hook_api_modify_serializer(self, view, serializer): |
47 | 25 |
from rest_framework import serializers |
48 | 26 | |
... | ... | |
120 | 98 |
'sub': fc_account.sub, |
121 | 99 |
} |
122 | 100 |
) |
101 | ||
102 |
def a2_hook_redirect_logout_list(self, request, **kwargs): |
|
103 |
from django.urls import reverse |
|
104 | ||
105 |
from . import utils |
|
106 |
from .models import FcAuthenticator |
|
107 | ||
108 |
try: |
|
109 |
authenticator = FcAuthenticator.objects.get() |
|
110 |
except FcAuthenticator.DoesNotExist: |
|
111 |
return [] |
|
112 | ||
113 |
url = utils.build_logout_url(request, authenticator.logout_url, next_url=reverse('auth_logout')) |
|
114 |
# url is assumed empty if no active session on the OP. |
|
115 |
if url: |
|
116 |
return [url] |
|
117 |
return [] |
src/authentic2_auth_oidc/apps.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
import logging |
|
18 | ||
17 | 19 |
import django.apps |
20 |
import requests |
|
18 | 21 |
from django import template |
19 | 22 | |
20 | 23 | |
21 |
class Plugin: |
|
22 |
def revoke_token(self, provider, access_token): |
|
23 |
import logging |
|
24 | ||
25 |
import requests |
|
26 | ||
27 |
logger = logging.getLogger(__name__) |
|
28 | ||
29 |
url = provider.token_revocation_endpoint |
|
30 |
try: |
|
31 |
response = requests.post( |
|
32 |
url, |
|
33 |
auth=(provider.client_id, provider.client_secret), |
|
34 |
data={'token': access_token, 'token_type': 'access_token'}, |
|
35 |
timeout=10, |
|
36 |
) |
|
37 |
except requests.RequestException as e: |
|
38 |
logger.warning('failed to revoke access token from OIDC provider %s: %s', provider.issuer, e) |
|
39 |
return |
|
40 |
try: |
|
41 |
response.raise_for_status() |
|
42 |
except requests.RequestException as e: |
|
43 |
try: |
|
44 |
content = response.json() |
|
45 |
except ValueError: |
|
46 |
content = None |
|
47 |
logger.warning( |
|
48 |
'failed to revoke access token from OIDC provider %s: %s, %s', provider.issuer, e, content |
|
49 |
) |
|
50 |
return |
|
51 |
logger.info('revoked token from OIDC provider %s', provider.issuer) |
|
52 | ||
53 |
def redirect_logout_list(self, request, next=None): |
|
54 |
from django.urls import reverse |
|
55 | ||
56 |
from authentic2.utils.misc import make_url |
|
57 | ||
58 |
from .models import OIDCProvider |
|
59 | ||
60 |
tokens = request.session.get('auth_oidc', {}).get('tokens', []) |
|
61 |
urls = [] |
|
62 |
if tokens: |
|
63 |
for token in tokens: |
|
64 |
provider = OIDCProvider.objects.get(pk=token['provider_pk']) |
|
65 |
# ignore providers wihtout SLO |
|
66 |
if not provider.end_session_endpoint: |
|
67 |
continue |
|
68 |
params = {} |
|
69 |
if 'id_token' in token['token_response']: |
|
70 |
params['id_token_hint'] = token['token_response']['id_token'] |
|
71 |
if 'access_token' in token['token_response'] and provider.token_revocation_endpoint: |
|
72 |
self.revoke_token(provider, token['token_response']['access_token']) |
|
73 |
params['post_logout_redirect_uri'] = request.build_absolute_uri(reverse('auth_logout')) |
|
74 |
urls.append(make_url(provider.end_session_endpoint, params=params)) |
|
75 |
return urls |
|
76 | ||
77 | ||
78 | 24 |
class AppConfig(django.apps.AppConfig): |
79 | ||
80 | 25 |
name = 'authentic2_auth_oidc' |
81 | 26 | |
82 |
def get_a2_plugin(self): |
|
83 |
return Plugin() |
|
84 | ||
85 | 27 |
def ready(self): |
86 | 28 |
from django.db.models.signals import pre_save |
87 | 29 | |
... | ... | |
108 | 50 |
return [ |
109 | 51 |
template.loader.get_template('authentic2_auth_oidc/manager_user_sidebar.html').render(context) |
110 | 52 |
] |
53 | ||
54 |
def a2_hook_redirect_logout_list(self, request, **kwargs): |
|
55 |
from django.urls import reverse |
|
56 | ||
57 |
from authentic2.utils.misc import make_url |
|
58 | ||
59 |
from .models import OIDCProvider |
|
60 | ||
61 |
tokens = request.session.get('auth_oidc', {}).get('tokens', []) |
|
62 |
urls = [] |
|
63 |
if tokens: |
|
64 |
for token in tokens: |
|
65 |
provider = OIDCProvider.objects.get(pk=token['provider_pk']) |
|
66 |
# ignore providers wihtout SLO |
|
67 |
if not provider.end_session_endpoint: |
|
68 |
continue |
|
69 |
params = {} |
|
70 |
if 'id_token' in token['token_response']: |
|
71 |
params['id_token_hint'] = token['token_response']['id_token'] |
|
72 |
if 'access_token' in token['token_response'] and provider.token_revocation_endpoint: |
|
73 |
self._revoke_token(provider, token['token_response']['access_token']) |
|
74 |
params['post_logout_redirect_uri'] = request.build_absolute_uri(reverse('auth_logout')) |
|
75 |
urls.append(make_url(provider.end_session_endpoint, params=params)) |
|
76 |
return urls |
|
77 | ||
78 |
@classmethod |
|
79 |
def _revoke_token(cls, provider, access_token): |
|
80 |
logger = logging.getLogger(__name__) |
|
81 | ||
82 |
url = provider.token_revocation_endpoint |
|
83 |
try: |
|
84 |
response = requests.post( |
|
85 |
url, |
|
86 |
auth=(provider.client_id, provider.client_secret), |
|
87 |
data={'token': access_token, 'token_type': 'access_token'}, |
|
88 |
timeout=10, |
|
89 |
) |
|
90 |
except requests.RequestException as e: |
|
91 |
logger.warning('failed to revoke access token from OIDC provider %s: %s', provider.issuer, e) |
|
92 |
return |
|
93 |
try: |
|
94 |
response.raise_for_status() |
|
95 |
except requests.RequestException as e: |
|
96 |
try: |
|
97 |
content = response.json() |
|
98 |
except ValueError: |
|
99 |
content = None |
|
100 |
logger.warning( |
|
101 |
'failed to revoke access token from OIDC provider %s: %s, %s', provider.issuer, e, content |
|
102 |
) |
|
103 |
return |
|
104 |
logger.info('revoked token from OIDC provider %s', provider.issuer) |
src/authentic2_auth_saml/apps.py | ||
---|---|---|
20 | 20 | |
21 | 21 | |
22 | 22 |
class AppConfig(django.apps.AppConfig): |
23 | ||
24 | 23 |
name = 'authentic2_auth_saml' |
25 | 24 | |
26 | 25 |
def ready(self): |
... | ... | |
54 | 53 |
return [ |
55 | 54 |
template.loader.get_template('authentic2_auth_saml/manager_user_sidebar.html').render(context) |
56 | 55 |
] |
56 | ||
57 |
def a2_hook_redirect_logout_list(self, request, **kwargs): |
|
58 |
from mellon.views import logout |
|
59 | ||
60 |
if 'mellon_session' in request.session: |
|
61 |
response = logout(request) |
|
62 |
if 'Location' in response: |
|
63 |
return [response['Location']] |
|
64 |
return [] |
src/authentic2_auth_saml/backends.py | ||
---|---|---|
38 | 38 |
import lasso |
39 | 39 | |
40 | 40 |
return lasso.SAML2_AUTHN_CONTEXT_PREVIOUS_SESSION |
41 | ||
42 |
def redirect_logout_list(self, request, next_url=None): |
|
43 |
from mellon.views import logout |
|
44 | ||
45 |
if 'mellon_session' in request.session: |
|
46 |
response = logout(request) |
|
47 |
if 'Location' in response: |
|
48 |
return [response['Location']] |
|
49 |
return [] |
|
50 |
- |