all: general maintenance, prepare for pyright
This commit is contained in:
parent
865abc005a
commit
9267d0c1dd
|
@ -304,7 +304,9 @@ class PropertyMapping(UUIDModel):
|
|||
form = ""
|
||||
objects = InheritanceManager()
|
||||
|
||||
def evaluate(self, user: User, request: HttpRequest, **kwargs) -> Any:
|
||||
def evaluate(
|
||||
self, user: Optional[User], request: Optional[HttpRequest], **kwargs
|
||||
) -> Any:
|
||||
"""Evaluate `self.expression` using `**kwargs` as Context."""
|
||||
try:
|
||||
expression = NATIVE_ENVIRONMENT.from_string(self.expression)
|
||||
|
|
|
@ -19,7 +19,7 @@ from structlog import get_logger
|
|||
from passbook.audit.models import Event, EventAction
|
||||
from passbook.factors.otp.forms import OTPSetupForm
|
||||
from passbook.factors.otp.utils import otpauth_url
|
||||
from passbook.lib.boilerplate import NeverCacheMixin
|
||||
from passbook.lib.mixins import NeverCacheMixin
|
||||
from passbook.lib.config import CONFIG
|
||||
|
||||
OTP_SESSION_KEY = "passbook_factors_otp_key"
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
"""passbook django boilerplate code"""
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.cache import never_cache
|
||||
|
||||
|
||||
class NeverCacheMixin:
|
||||
"""Use never_cache as mixin for CBV"""
|
||||
|
||||
@method_decorator(never_cache)
|
||||
def dispatch(self, *args, **kwargs):
|
||||
"""Use never_cache as mixin for CBV"""
|
||||
return super().dispatch(*args, **kwargs)
|
|
@ -1,4 +1,5 @@
|
|||
"""passbook util mixins"""
|
||||
from django.views.decorators.cache import never_cache
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
|
@ -10,3 +11,12 @@ class CSRFExemptMixin:
|
|||
def dispatch(self, *args, **kwargs):
|
||||
"""wrapper to apply @csrf_exempt to CBV"""
|
||||
return super().dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
class NeverCacheMixin:
|
||||
"""Use never_cache as mixin for CBV"""
|
||||
|
||||
@method_decorator(never_cache)
|
||||
def dispatch(self, *args, **kwargs):
|
||||
"""Use never_cache as mixin for CBV"""
|
||||
return super().dispatch(*args, **kwargs)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""policy structures"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, List
|
||||
from typing import TYPE_CHECKING, Tuple
|
||||
|
||||
from django.db.models import Model
|
||||
from django.http import HttpRequest
|
||||
|
@ -27,8 +27,8 @@ class PolicyRequest:
|
|||
class PolicyResult:
|
||||
"""Small data-class to hold policy results"""
|
||||
|
||||
passing: bool = False
|
||||
messages: List[str] = []
|
||||
passing: bool
|
||||
messages: Tuple[str]
|
||||
|
||||
def __init__(self, passing: bool, *messages: str):
|
||||
self.passing = passing
|
||||
|
|
|
@ -15,24 +15,32 @@ from passbook.policies.engine import PolicyEngine
|
|||
LOGGER = get_logger()
|
||||
|
||||
|
||||
def client_related_provider(client: Client) -> Optional[Provider]:
|
||||
"""Lookup related Application from Client"""
|
||||
# because oidc_provider is also used by app_gw, we can't be
|
||||
# sure an OpenIDPRovider instance exists. hence we look through all related models
|
||||
# and choose the one that inherits from Provider, which is guaranteed to
|
||||
# have the application property
|
||||
collector = Collector(using="default")
|
||||
collector.collect([client])
|
||||
for _, related in collector.data.items():
|
||||
related_object = next(iter(related))
|
||||
if isinstance(related_object, Provider):
|
||||
return related_object
|
||||
return None
|
||||
|
||||
|
||||
def check_permissions(
|
||||
request: HttpRequest, user: User, client: Client
|
||||
) -> Optional[HttpResponse]:
|
||||
"""Check permissions, used for
|
||||
https://django-oidc-provider.readthedocs.io/en/latest/
|
||||
sections/settings.html#oidc-after-userlogin-hook"""
|
||||
provider = client_related_provider(client)
|
||||
if not provider:
|
||||
return redirect("passbook_providers_oauth:oauth2-permission-denied")
|
||||
try:
|
||||
# because oidc_provider is also used by app_gw, we can't be
|
||||
# sure an OpenIDPRovider instance exists. hence we look through all related models
|
||||
# and choose the one that inherits from Provider, which is guaranteed to
|
||||
# have the application property
|
||||
collector = Collector(using="default")
|
||||
collector.collect([client])
|
||||
for _, related in collector.data.items():
|
||||
related_object = next(iter(related))
|
||||
if isinstance(related_object, Provider):
|
||||
application = related_object.application
|
||||
break
|
||||
application = provider.application
|
||||
except Application.DoesNotExist:
|
||||
return redirect("passbook_providers_oauth:oauth2-permission-denied")
|
||||
LOGGER.debug(
|
||||
|
|
|
@ -42,7 +42,11 @@ class AccessRequiredView(AccessMixin, View):
|
|||
application = get_object_or_404(
|
||||
Application, slug=self.kwargs["application"]
|
||||
)
|
||||
self._provider = get_object_or_404(SAMLProvider, pk=application.provider_id)
|
||||
provider: SAMLProvider = get_object_or_404(
|
||||
SAMLProvider, pk=application.provider_id
|
||||
)
|
||||
self._provider = provider
|
||||
return self._provider
|
||||
return self._provider
|
||||
|
||||
def _has_access(self) -> bool:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Core OAauth Views"""
|
||||
from typing import Callable, Optional
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
|
@ -23,7 +24,7 @@ LOGGER = get_logger()
|
|||
class OAuthClientMixin:
|
||||
"Mixin for getting OAuth client for a source."
|
||||
|
||||
client_class = None
|
||||
client_class: Optional[Callable] = None
|
||||
|
||||
def get_client(self, source):
|
||||
"Get instance of the OAuth client for this source."
|
||||
|
|
|
@ -21,13 +21,15 @@ class SAMLSource(Source):
|
|||
|
||||
@property
|
||||
def login_button(self):
|
||||
url = reverse_lazy("passbook_sources_saml:login", kwargs={"source": self.slug})
|
||||
url = reverse_lazy(
|
||||
"passbook_sources_saml:login", kwargs={"source_slug": self.slug}
|
||||
)
|
||||
return url, "", self.name
|
||||
|
||||
@property
|
||||
def additional_info(self):
|
||||
metadata_url = reverse_lazy(
|
||||
"passbook_sources_saml:metadata", kwargs={"source": self}
|
||||
"passbook_sources_saml:metadata", kwargs={"source_slug": self}
|
||||
)
|
||||
return f'<a href="{metadata_url}" class="btn btn-default btn-sm">Metadata Download</a>'
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ from django.urls import path
|
|||
from passbook.sources.saml.views import ACSView, InitiateView, MetadataView, SLOView
|
||||
|
||||
urlpatterns = [
|
||||
path("<slug:source>/", InitiateView.as_view(), name="login"),
|
||||
path("<slug:source>/acs/", ACSView.as_view(), name="acs"),
|
||||
path("<slug:source>/slo/", SLOView.as_view(), name="slo"),
|
||||
path("<slug:source>/metadata/", MetadataView.as_view(), name="metadata"),
|
||||
path("<slug:source_slug>/", InitiateView.as_view(), name="login"),
|
||||
path("<slug:source_slug>/acs/", ACSView.as_view(), name="acs"),
|
||||
path("<slug:source_slug>/slo/", SLOView.as_view(), name="slo"),
|
||||
path("<slug:source_slug>/metadata/", MetadataView.as_view(), name="metadata"),
|
||||
]
|
||||
|
|
|
@ -24,9 +24,9 @@ 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:
|
||||
def get(self, request: HttpRequest, source_slug: str) -> HttpResponse:
|
||||
"""Replies with an XHTML SSO Request."""
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
|
||||
if not source.enabled:
|
||||
raise Http404
|
||||
sso_destination = request.GET.get("next", None)
|
||||
|
@ -56,9 +56,9 @@ class InitiateView(View):
|
|||
class ACSView(View):
|
||||
"""AssertionConsumerService, consume assertion and log user in"""
|
||||
|
||||
def post(self, request: HttpRequest, source: str) -> HttpResponse:
|
||||
def post(self, request: HttpRequest, source_slug: str) -> HttpResponse:
|
||||
"""Handles a POSTed SSO Assertion and logs the user in."""
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
|
||||
if not source.enabled:
|
||||
raise Http404
|
||||
# sso_session = request.POST.get('RelayState', None)
|
||||
|
@ -74,9 +74,9 @@ class ACSView(View):
|
|||
class SLOView(View):
|
||||
"""Single-Logout-View"""
|
||||
|
||||
def dispatch(self, request: HttpRequest, source: str) -> HttpResponse:
|
||||
def dispatch(self, request: HttpRequest, source_slug: str) -> HttpResponse:
|
||||
"""Replies with an XHTML SSO Request."""
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
|
||||
if not source.enabled:
|
||||
raise Http404
|
||||
logout(request)
|
||||
|
@ -93,9 +93,9 @@ class SLOView(View):
|
|||
class MetadataView(View):
|
||||
"""Return XML Metadata for IDP"""
|
||||
|
||||
def dispatch(self, request: HttpRequest, source: str) -> HttpResponse:
|
||||
def dispatch(self, request: HttpRequest, source_slug: str) -> HttpResponse:
|
||||
"""Replies with the XML Metadata SPSSODescriptor."""
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source)
|
||||
source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
|
||||
entity_id = get_entity_id(request, source)
|
||||
return render_xml(
|
||||
request,
|
||||
|
|
3
pyrightconfig.json
Normal file
3
pyrightconfig.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"reportMissingTypeStubs": false
|
||||
}
|
Reference in a new issue