This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/passbook/sources/saml/views.py

109 lines
3.9 KiB
Python
Raw Normal View History

2019-11-07 16:02:56 +00:00
"""saml sp views"""
import base64
from defusedxml import ElementTree
from django.contrib.auth import login, logout
2019-11-07 17:02:59 +00:00
from django.http import Http404, HttpRequest, HttpResponse
2019-11-07 16:02:56 +00:00
from django.shortcuts import get_object_or_404, redirect, render, reverse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from passbook.providers.saml.base import get_random_id, get_time_string
from passbook.providers.saml.utils import nice64
from passbook.providers.saml.views import render_xml
from passbook.sources.saml.models import SAMLSource
2019-12-31 11:51:16 +00:00
from passbook.sources.saml.utils import (
_get_user_from_response,
build_full_url,
get_entity_id,
)
2019-11-07 16:02:56 +00:00
from passbook.sources.saml.xml_render import get_authnrequest_xml
class InitiateView(View):
"""Get the Form with SAML Request, which sends us to the IDP"""
def get(self, request: HttpRequest, source: str) -> HttpResponse:
"""Replies with an XHTML SSO Request."""
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
if not source.enabled:
raise Http404
2019-12-31 11:51:16 +00:00
sso_destination = request.GET.get("next", None)
request.session["sso_destination"] = sso_destination
2019-11-07 16:02:56 +00:00
parameters = {
2019-12-31 11:51:16 +00:00
"ACS_URL": build_full_url("acs", request, source),
"DESTINATION": source.idp_url,
"AUTHN_REQUEST_ID": get_random_id(),
"ISSUE_INSTANT": get_time_string(),
"ISSUER": get_entity_id(request, source),
2019-11-07 16:02:56 +00:00
}
authn_req = get_authnrequest_xml(parameters, signed=False)
_request = nice64(str.encode(authn_req))
2019-12-31 11:51:16 +00:00
return render(
request,
"saml/sp/login.html",
{
"request_url": source.idp_url,
"request": _request,
"token": sso_destination,
"source": source,
},
)
2019-11-07 16:02:56 +00:00
2019-12-31 11:51:16 +00:00
@method_decorator(csrf_exempt, name="dispatch")
2019-11-07 16:02:56 +00:00
class ACSView(View):
"""AssertionConsumerService, consume assertion and log user in"""
def post(self, request: HttpRequest, source: str) -> HttpResponse:
"""Handles a POSTed SSO Assertion and logs the user in."""
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
if not source.enabled:
raise Http404
2019-11-07 16:02:56 +00:00
# sso_session = request.POST.get('RelayState', None)
2019-12-31 11:51:16 +00:00
data = request.POST.get("SAMLResponse", None)
2019-11-07 16:02:56 +00:00
response = base64.b64decode(data)
root = ElementTree.fromstring(response)
user = _get_user_from_response(root)
# attributes = _get_attributes_from_response(root)
2019-12-31 11:51:16 +00:00
login(request, user, backend="django.contrib.auth.backends.ModelBackend")
return redirect(reverse("passbook_core:overview"))
2019-11-07 16:02:56 +00:00
class SLOView(View):
"""Single-Logout-View"""
def dispatch(self, request: HttpRequest, source: str) -> HttpResponse:
"""Replies with an XHTML SSO Request."""
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
if not source.enabled:
raise Http404
2019-11-07 16:02:56 +00:00
logout(request)
2019-12-31 11:51:16 +00:00
return render(
request,
"saml/sp/sso_single_logout.html",
{
"idp_logout_url": source.idp_logout_url,
"autosubmit": source.auto_logout,
},
)
2019-11-07 16:02:56 +00:00
class MetadataView(View):
"""Return XML Metadata for IDP"""
def dispatch(self, request: HttpRequest, source: str) -> HttpResponse:
"""Replies with the XML Metadata SPSSODescriptor."""
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
entity_id = get_entity_id(request, source)
2019-12-31 11:51:16 +00:00
return render_xml(
request,
"saml/sp/xml/spssodescriptor.xml",
{
"acs_url": build_full_url("acs", request, source),
"entity_id": entity_id,
"cert_public_key": source.signing_cert,
},
)