cleanup SAML urls
This commit is contained in:
parent
9b131b619f
commit
fcb5d36e07
|
@ -42,7 +42,7 @@ class SAMLProvider(Provider):
|
||||||
"""Get link to download XML metadata for admin interface"""
|
"""Get link to download XML metadata for admin interface"""
|
||||||
try:
|
try:
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
return reverse('passbook_saml_idp:metadata_xml',
|
return reverse('passbook_saml_idp:saml-metadata',
|
||||||
kwargs={'application': self.application.slug})
|
kwargs={'application': self.application.slug})
|
||||||
except Provider.application.RelatedObjectDoesNotExist:
|
except Provider.application.RelatedObjectDoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<a href="{% url 'passbook_saml_idp:metadata_xml' %}" class="btn btn-primary"><clr-icon shape="download"></clr-icon>{% trans 'Download Metadata' %}</a>
|
<a href="{% url 'passbook_saml_idp:saml-metadata' %}" class="btn btn-primary"><clr-icon shape="download"></clr-icon>{% trans 'Download Metadata' %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,13 +4,14 @@ from django.urls import path
|
||||||
from passbook.saml_idp import views
|
from passbook.saml_idp import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('login/<slug:application>/',
|
path('<slug:application>/login/',
|
||||||
views.LoginBeginView.as_view(), name="saml_login_begin"),
|
views.LoginBeginView.as_view(), name="saml-login"),
|
||||||
path('login/<slug:application>/initiate/',
|
path('<slug:application>/login/initiate/',
|
||||||
views.InitiateLoginView.as_view(), name="saml_login_init"),
|
views.InitiateLoginView.as_view(), name="saml-login-initiate"),
|
||||||
path('login/<slug:application>/process/',
|
path('<slug:application>/login/process/',
|
||||||
views.LoginProcessView.as_view(), name='saml_login_process'),
|
views.LoginProcessView.as_view(), name='saml-login-process'),
|
||||||
path('logout/', views.LogoutView.as_view(), name="saml_logout"),
|
path('<slug:application>/logout/', views.LogoutView.as_view(), name="saml-logout"),
|
||||||
path('metadata/<slug:application>/',
|
path('<slug:application>/logout/slo/', views.SLOLogout.as_view(), name="saml-logout-slo"),
|
||||||
views.DescriptorDownloadView.as_view(), name='metadata_xml'),
|
path('<slug:application>/metadata/',
|
||||||
|
views.DescriptorDownloadView.as_view(), name='saml-metadata'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,6 +14,7 @@ from django.views.decorators.csrf import csrf_exempt
|
||||||
from signxml.util import strip_pem_header
|
from signxml.util import strip_pem_header
|
||||||
|
|
||||||
from passbook.core.models import Application
|
from passbook.core.models import Application
|
||||||
|
from passbook.core.policies import PolicyEngine
|
||||||
from passbook.lib.config import CONFIG
|
from passbook.lib.config import CONFIG
|
||||||
from passbook.lib.mixins import CSRFExemptMixin
|
from passbook.lib.mixins import CSRFExemptMixin
|
||||||
from passbook.lib.utils.template import render_to_string
|
from passbook.lib.utils.template import render_to_string
|
||||||
|
@ -75,7 +76,7 @@ class LoginBeginView(LoginRequiredMixin, View):
|
||||||
return HttpResponseBadRequest('the SAML request payload is missing')
|
return HttpResponseBadRequest('the SAML request payload is missing')
|
||||||
|
|
||||||
request.session['RelayState'] = source.get('RelayState', '')
|
request.session['RelayState'] = source.get('RelayState', '')
|
||||||
return redirect(reverse('passbook_saml_idp:saml_login_process', kwargs={
|
return redirect(reverse('passbook_saml_idp:saml-login-process', kwargs={
|
||||||
'application': application
|
'application': application
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -94,17 +95,22 @@ class RedirectToSPView(LoginRequiredMixin, View):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LoginProcessView(ProviderMixin, LoginRequiredMixin, View):
|
class LoginProcessView(ProviderMixin, LoginRequiredMixin, View):
|
||||||
"""Processor-based login continuation.
|
"""Processor-based login continuation.
|
||||||
Presents a SAML 2.0 Assertion for POSTing back to the Service Provider."""
|
Presents a SAML 2.0 Assertion for POSTing back to the Service Provider."""
|
||||||
|
|
||||||
|
def _has_access(self):
|
||||||
|
"""Check if user has access to application"""
|
||||||
|
policy_engine = PolicyEngine(self.provider.application.policies.all())
|
||||||
|
policy_engine.for_user(self.request.user)
|
||||||
|
return policy_engine.result
|
||||||
|
|
||||||
def get(self, request, application):
|
def get(self, request, application):
|
||||||
"""Handle get request, i.e. render form"""
|
"""Handle get request, i.e. render form"""
|
||||||
LOGGER.debug("Request: %s", request)
|
LOGGER.debug("Request: %s", request)
|
||||||
# Check if user has access
|
# Check if user has access
|
||||||
access = True
|
if self.provider.application.skip_authorization and self._has_access():
|
||||||
# TODO: Check access here
|
|
||||||
if self.provider.application.skip_authorization and access:
|
|
||||||
ctx = self.provider.processor.generate_response()
|
ctx = self.provider.processor.generate_response()
|
||||||
# TODO: AuditLog Skipped Authz
|
# TODO: AuditLog Skipped Authz
|
||||||
return RedirectToSPView.as_view()(
|
return RedirectToSPView.as_view()(
|
||||||
|
@ -122,9 +128,7 @@ class LoginProcessView(ProviderMixin, LoginRequiredMixin, View):
|
||||||
"""Handle post request, return back to ACS"""
|
"""Handle post request, return back to ACS"""
|
||||||
LOGGER.debug("Request: %s", request)
|
LOGGER.debug("Request: %s", request)
|
||||||
# Check if user has access
|
# Check if user has access
|
||||||
access = True
|
if request.POST.get('ACSUrl', None) and self._has_access():
|
||||||
# TODO: Check access here
|
|
||||||
if request.POST.get('ACSUrl', None) and access:
|
|
||||||
# User accepted request
|
# User accepted request
|
||||||
# TODO: AuditLog accepted
|
# TODO: AuditLog accepted
|
||||||
return RedirectToSPView.as_view()(
|
return RedirectToSPView.as_view()(
|
||||||
|
@ -144,7 +148,7 @@ class LogoutView(CSRFExemptMixin, LoginRequiredMixin, View):
|
||||||
returns a standard logged-out page. (SalesForce and others use this method,
|
returns a standard logged-out page. (SalesForce and others use this method,
|
||||||
though it's technically not SAML 2.0)."""
|
though it's technically not SAML 2.0)."""
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request, application):
|
||||||
"""Perform logout"""
|
"""Perform logout"""
|
||||||
logout(request)
|
logout(request)
|
||||||
|
|
||||||
|
@ -164,11 +168,10 @@ class SLOLogout(CSRFExemptMixin, LoginRequiredMixin, View):
|
||||||
"""Receives a SAML 2.0 LogoutRequest from a Service Provider,
|
"""Receives a SAML 2.0 LogoutRequest from a Service Provider,
|
||||||
logs out the user and returns a standard logged-out page."""
|
logs out the user and returns a standard logged-out page."""
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request, application):
|
||||||
"""Perform logout"""
|
"""Perform logout"""
|
||||||
request.session['SAMLRequest'] = request.POST['SAMLRequest']
|
request.session['SAMLRequest'] = request.POST['SAMLRequest']
|
||||||
# TODO: Parse SAML LogoutRequest from POST data, similar to login_process().
|
# TODO: Parse SAML LogoutRequest from POST data, similar to login_process().
|
||||||
# TODO: Add a URL dispatch for this view.
|
|
||||||
# TODO: Modify the base processor to handle logouts?
|
# TODO: Modify the base processor to handle logouts?
|
||||||
# TODO: Combine this with login_process(), since they are so very similar?
|
# TODO: Combine this with login_process(), since they are so very similar?
|
||||||
# TODO: Format a LogoutResponse and return it to the browser.
|
# TODO: Format a LogoutResponse and return it to the browser.
|
||||||
|
@ -183,8 +186,8 @@ class DescriptorDownloadView(ProviderMixin, View):
|
||||||
def get(self, request, application):
|
def get(self, request, application):
|
||||||
"""Replies with the XML Metadata IDSSODescriptor."""
|
"""Replies with the XML Metadata IDSSODescriptor."""
|
||||||
entity_id = CONFIG.y('saml_idp.issuer')
|
entity_id = CONFIG.y('saml_idp.issuer')
|
||||||
slo_url = request.build_absolute_uri(reverse('passbook_saml_idp:saml_logout'))
|
slo_url = request.build_absolute_uri(reverse('passbook_saml_idp:saml-logout'))
|
||||||
sso_url = request.build_absolute_uri(reverse('passbook_saml_idp:saml_login_begin', kwargs={
|
sso_url = request.build_absolute_uri(reverse('passbook_saml_idp:saml-login', kwargs={
|
||||||
'application': application
|
'application': application
|
||||||
}))
|
}))
|
||||||
pubkey = strip_pem_header(self.provider.signing_cert.replace('\r', '')).replace('\n', '')
|
pubkey = strip_pem_header(self.provider.signing_cert.replace('\r', '')).replace('\n', '')
|
||||||
|
|
Reference in New Issue