authentik.providers.saml.tasks
SAML Provider tasks
1"""SAML Provider tasks""" 2 3import requests 4from django.contrib.auth import get_user_model 5from dramatiq.actor import actor 6from structlog.stdlib import get_logger 7 8from authentik.events.models import Event, EventAction 9from authentik.providers.saml.models import SAMLProvider 10from authentik.providers.saml.processors.logout_request import LogoutRequestProcessor 11from authentik.providers.saml.processors.logout_request_parser import LogoutRequest 12from authentik.providers.saml.processors.logout_response_processor import LogoutResponseProcessor 13 14LOGGER = get_logger() 15User = get_user_model() 16 17 18@actor(description="Send SAML LogoutRequest to a Service Provider") 19def send_saml_logout_request( 20 provider_pk: int, 21 sls_url: str, 22 name_id: str, 23 name_id_format: str, 24 session_index: str, 25 issuer: str, 26): 27 """Send SAML LogoutRequest to a Service Provider using session data""" 28 provider = SAMLProvider.objects.filter(pk=provider_pk).first() 29 if not provider: 30 LOGGER.error( 31 "Provider not found for SAML logout request", 32 provider_pk=provider_pk, 33 session_index=session_index, 34 ) 35 return False 36 37 LOGGER.debug( 38 "Sending SAML logout request", 39 provider=provider.name, 40 session_index=session_index, 41 ) 42 43 # Note: We don't need the user object for the logout request itself 44 processor = LogoutRequestProcessor( 45 provider=provider, 46 user=None, 47 destination=sls_url, 48 name_id=name_id, 49 name_id_format=name_id_format, 50 session_index=session_index, 51 issuer=issuer, 52 ) 53 54 return send_post_logout_request(provider, processor) 55 56 57def send_post_logout_request(provider: SAMLProvider, processor: LogoutRequestProcessor) -> bool: 58 """Send LogoutRequest using POST binding""" 59 encoded_request = processor.encode_post() 60 61 form_data = { 62 "SAMLRequest": encoded_request, 63 } 64 65 if processor.relay_state: 66 form_data["RelayState"] = processor.relay_state 67 68 response = requests.post( 69 provider.sls_url, 70 data=form_data, 71 timeout=10, 72 headers={ 73 "Content-Type": "application/x-www-form-urlencoded", 74 }, 75 allow_redirects=True, 76 ) 77 response.raise_for_status() 78 79 LOGGER.debug( 80 "Sent POST logout request", 81 provider=provider, 82 status_code=response.status_code, 83 ) 84 85 return True 86 87 88@actor(description="Send SAML LogoutResponse to a Service Provider (backchannel)") 89def send_saml_logout_response( 90 provider_pk: int, 91 sls_url: str, 92 logout_request_id: str | None = None, 93 relay_state: str | None = None, 94 issuer: str | None = None, 95): 96 """Send SAML LogoutResponse to a Service Provider using backchannel (server-to-server)""" 97 provider = SAMLProvider.objects.filter(pk=provider_pk).first() 98 if not provider: 99 LOGGER.error( 100 "Provider not found for SAML logout response", 101 provider_pk=provider_pk, 102 ) 103 return False 104 105 LOGGER.debug( 106 "Sending backchannel SAML logout response", 107 provider=provider.name, 108 sls_url=sls_url, 109 ) 110 111 # Create a minimal LogoutRequest object for the response processor 112 # We only need the ID and relay_state for building the response 113 logout_request = None 114 if logout_request_id: 115 logout_request = LogoutRequest() 116 logout_request.id = logout_request_id 117 logout_request.relay_state = relay_state 118 119 # Build the logout response 120 processor = LogoutResponseProcessor( 121 provider=provider, 122 logout_request=logout_request, 123 destination=sls_url, 124 relay_state=relay_state, 125 issuer=issuer, 126 ) 127 128 encoded_response = processor.encode_post() 129 130 form_data = { 131 "SAMLResponse": encoded_response, 132 } 133 134 if relay_state: 135 form_data["RelayState"] = relay_state 136 137 # Send the logout response to the SP 138 try: 139 response = requests.post( 140 sls_url, 141 data=form_data, 142 timeout=10, 143 headers={ 144 "Content-Type": "application/x-www-form-urlencoded", 145 }, 146 allow_redirects=True, 147 ) 148 response.raise_for_status() 149 150 LOGGER.info( 151 "Successfully sent backchannel logout response to SP", 152 provider=provider.name, 153 sls_url=sls_url, 154 status_code=response.status_code, 155 ) 156 return True 157 158 except requests.exceptions.RequestException as exc: 159 LOGGER.warning( 160 "Failed to send backchannel logout response to SP", 161 provider=provider.name, 162 sls_url=sls_url, 163 error=str(exc), 164 ) 165 Event.new( 166 EventAction.CONFIGURATION_ERROR, 167 provider=provider, 168 message=f"Backchannel logout response failed: {str(exc)}", 169 ).save() 170 return False
360class User(SerializerModel, AttributesMixin, AbstractUser): 361 """authentik User model, based on django's contrib auth user model.""" 362 363 # Overwriting PermissionsMixin: permissions are handled by roles. 364 # (This knowingly violates the Liskov substitution principle. It is better to fail loudly.) 365 user_permissions = None 366 367 uuid = models.UUIDField(default=uuid4, editable=False, unique=True) 368 name = models.TextField(help_text=_("User's display name.")) 369 path = models.TextField(default="users") 370 type = models.TextField(choices=UserTypes.choices, default=UserTypes.INTERNAL) 371 372 sources = models.ManyToManyField("Source", through="UserSourceConnection") 373 groups = models.ManyToManyField("Group", related_name="users") 374 roles = models.ManyToManyField("authentik_rbac.Role", related_name="users", blank=True) 375 password_change_date = models.DateTimeField(auto_now_add=True) 376 377 last_updated = models.DateTimeField(auto_now=True) 378 379 objects = UserManager() 380 381 class Meta: 382 verbose_name = _("User") 383 verbose_name_plural = _("Users") 384 permissions = [ 385 ("reset_user_password", _("Reset Password")), 386 ("impersonate", _("Can impersonate other users")), 387 ("preview_user", _("Can preview user data sent to providers")), 388 ("view_user_applications", _("View applications the user has access to")), 389 ] 390 indexes = [ 391 models.Index(fields=["last_login"]), 392 models.Index(fields=["password_change_date"]), 393 models.Index(fields=["uuid"]), 394 models.Index(fields=["path"]), 395 models.Index(fields=["type"]), 396 models.Index(fields=["date_joined"]), 397 models.Index(fields=["last_updated"]), 398 ] 399 400 def __str__(self): 401 return self.username 402 403 @staticmethod 404 def default_path() -> str: 405 """Get the default user path""" 406 return User._meta.get_field("path").default 407 408 def all_groups(self) -> QuerySet[Group]: 409 """Recursively get all groups this user is a member of.""" 410 return self.groups.all().with_ancestors() 411 412 def all_roles(self) -> QuerySet[Role]: 413 """Get all roles of this user and all of its groups (recursively).""" 414 return Role.objects.filter(Q(users=self) | Q(groups__in=self.all_groups())).distinct() 415 416 def get_managed_role(self, create=False): 417 if create: 418 name = managed_role_name(self) 419 role, created = Role.objects.get_or_create(name=name, managed=name) 420 if created: 421 role.users.add(self) 422 return role 423 else: 424 return Role.objects.filter(name=managed_role_name(self)).first() 425 426 def get_all_model_perms_on_managed_role(self) -> QuerySet[RoleModelPermission]: 427 role = self.get_managed_role() 428 if not role: 429 return RoleModelPermission.objects.none() 430 return RoleModelPermission.objects.filter(role=role) 431 432 def get_all_obj_perms_on_managed_role(self) -> QuerySet[RoleObjectPermission]: 433 role = self.get_managed_role() 434 if not role: 435 return RoleObjectPermission.objects.none() 436 return RoleObjectPermission.objects.filter(role=role) 437 438 def assign_perms_to_managed_role( 439 self, 440 perms: str | list[str] | Permission | list[Permission], 441 obj: models.Model | None = None, 442 ): 443 if not perms: 444 return 445 role = self.get_managed_role(create=True) 446 role.assign_perms(perms, obj) 447 448 def remove_perms_from_managed_role( 449 self, 450 perms: str | list[str] | Permission | list[Permission], 451 obj: models.Model | None = None, 452 ): 453 role = self.get_managed_role() 454 if not role: 455 return None 456 role.remove_perms(perms, obj) 457 458 def remove_all_perms_from_managed_role(self): 459 role = self.get_managed_role() 460 if not role: 461 return None 462 RoleModelPermission.objects.filter(role=role).delete() 463 RoleObjectPermission.objects.filter(role=role).delete() 464 465 def group_attributes(self, request: HttpRequest | None = None) -> dict[str, Any]: 466 """Get a dictionary containing the attributes from all groups the user belongs to, 467 including the users attributes""" 468 final_attributes = {} 469 if request and hasattr(request, "brand"): 470 always_merger.merge(final_attributes, request.brand.attributes) 471 for group in self.all_groups().order_by("name"): 472 always_merger.merge(final_attributes, group.attributes) 473 always_merger.merge(final_attributes, self.attributes) 474 return final_attributes 475 476 def app_entitlements(self, app: Application | None) -> QuerySet[ApplicationEntitlement]: 477 """Get all entitlements this user has for `app`.""" 478 if not app: 479 return [] 480 all_groups = self.all_groups() 481 qs = app.applicationentitlement_set.filter( 482 Q( 483 Q(bindings__user=self) | Q(bindings__group__in=all_groups), 484 bindings__negate=False, 485 ) 486 | Q( 487 Q(~Q(bindings__user=self), bindings__user__isnull=False) 488 | Q(~Q(bindings__group__in=all_groups), bindings__group__isnull=False), 489 bindings__negate=True, 490 ), 491 bindings__enabled=True, 492 ).order_by("name") 493 return qs 494 495 def app_entitlements_attributes(self, app: Application | None) -> dict: 496 """Get a dictionary containing all merged attributes from app entitlements for `app`.""" 497 final_attributes = {} 498 for attrs in self.app_entitlements(app).values_list("attributes", flat=True): 499 always_merger.merge(final_attributes, attrs) 500 return final_attributes 501 502 @property 503 def serializer(self) -> Serializer: 504 from authentik.core.api.users import UserSerializer 505 506 return UserSerializer 507 508 @cached_property 509 def is_superuser(self) -> bool: 510 """Get supseruser status based on membership in a group with superuser status""" 511 return self.all_groups().filter(is_superuser=True).exists() 512 513 @property 514 def is_staff(self) -> bool: 515 """superuser == staff user""" 516 return self.is_superuser # type: ignore 517 518 # TODO: remove this after 2026. 519 @property 520 def ak_groups(self): 521 """This is a proxy for a renamed, deprecated field.""" 522 from authentik.events.models import Event 523 524 deprecation = "authentik.core.models.User.ak_groups" 525 replacement = "authentik.core.models.User.groups" 526 message_logger = ( 527 f"{deprecation} is deprecated and will be removed in a future version of " 528 f"authentik. Please use {replacement} instead." 529 ) 530 message_event = ( 531 f"{message_logger} This event will not be repeated until it expires (by " 532 "default: in 30 days). See authentik logs for every will invocation of this " 533 "deprecation." 534 ) 535 stacktrace = traceback.format_stack() 536 # The last line is this function, the next-to-last line is its caller 537 cause = stacktrace[-2] if len(stacktrace) > 1 else "Unknown, see stacktrace in logs" 538 if search := re.search(r'"(.*?)"', cause): 539 cause = f"Property mapping or Expression policy named {search.group(1)}" 540 541 LOGGER.warning( 542 "deprecation used", 543 message=message_logger, 544 deprecation=deprecation, 545 replacement=replacement, 546 cause=cause, 547 stacktrace=stacktrace, 548 ) 549 Event.log_deprecation( 550 deprecation, message=message_event, cause=cause, replacement=replacement 551 ) 552 return self.groups 553 554 def set_password(self, raw_password, signal=True, sender=None, request=None): 555 if self.pk and signal: 556 from authentik.core.signals import password_changed 557 558 if not sender: 559 sender = self 560 password_changed.send(sender=sender, user=self, password=raw_password, request=request) 561 self.password_change_date = now() 562 return super().set_password(raw_password) 563 564 @staticmethod 565 def validate_password_hash(password_hash: str): 566 """Validate that the value is a recognized Django password hash.""" 567 identify_hasher(password_hash) # Raises ValueError if invalid 568 569 def set_password_from_hash(self, password_hash: str, signal=True, sender=None, request=None): 570 """Set password directly from a pre-hashed value. 571 572 Unlike set_password(), this does not hash the input again. The provided value 573 must already be a valid Django password hash, and it is stored directly on the 574 user after validation. 575 576 Because no raw password is available, downstream password sync integrations 577 such as LDAP and Kerberos cannot be updated from this code path. 578 579 Raises ValueError if the hash format is not recognized. 580 """ 581 self.validate_password_hash(password_hash) 582 if self.pk and signal: 583 from authentik.core.signals import password_hash_changed 584 585 if not sender: 586 sender = self 587 password_hash_changed.send(sender=sender, user=self, request=request) 588 self.password = password_hash 589 self.password_change_date = now() 590 591 def check_password(self, raw_password: str) -> bool: 592 """ 593 Return a boolean of whether the raw_password was correct. Handles 594 hashing formats behind the scenes. 595 596 Slightly changed version which doesn't send a signal for such internal hash upgrades 597 """ 598 599 def setter(raw_password): 600 self.set_password(raw_password, signal=False) 601 # Password hash upgrades shouldn't be considered password changes. 602 self._password = None 603 self.save(update_fields=["password"]) 604 605 return check_password(raw_password, self.password, setter) 606 607 @property 608 def uid(self) -> str: 609 """Generate a globally unique UID, based on the user ID and the hashed secret key""" 610 return sha256(f"{self.id}-{get_unique_identifier()}".encode("ascii")).hexdigest() 611 612 def locale(self, request: HttpRequest | None = None) -> str: 613 """Get the locale the user has configured""" 614 if request and hasattr(request, "LANGUAGE_CODE"): 615 return request.LANGUAGE_CODE 616 try: 617 return self.attributes.get("settings", {}).get("locale", "") 618 619 except Exception as exc: # noqa 620 LOGGER.warning("Failed to get default locale", exc=exc) 621 if request: 622 return request.brand.locale 623 return "" 624 625 @property 626 def avatar(self) -> str: 627 """Get avatar, depending on authentik.avatar setting""" 628 return get_avatar(self)
authentik User model, based on django's contrib auth user model.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.
In the example::
class Pizza(Model):
toppings = ManyToManyField(Topping, related_name='pizzas')
Pizza.toppings and Topping.pizzas are ManyToManyDescriptor
instances.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.
In the example::
class Pizza(Model):
toppings = ManyToManyField(Topping, related_name='pizzas')
Pizza.toppings and Topping.pizzas are ManyToManyDescriptor
instances.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.
In the example::
class Pizza(Model):
toppings = ManyToManyField(Topping, related_name='pizzas')
Pizza.toppings and Topping.pizzas are ManyToManyDescriptor
instances.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
403 @staticmethod 404 def default_path() -> str: 405 """Get the default user path""" 406 return User._meta.get_field("path").default
Get the default user path
408 def all_groups(self) -> QuerySet[Group]: 409 """Recursively get all groups this user is a member of.""" 410 return self.groups.all().with_ancestors()
Recursively get all groups this user is a member of.
412 def all_roles(self) -> QuerySet[Role]: 413 """Get all roles of this user and all of its groups (recursively).""" 414 return Role.objects.filter(Q(users=self) | Q(groups__in=self.all_groups())).distinct()
Get all roles of this user and all of its groups (recursively).
416 def get_managed_role(self, create=False): 417 if create: 418 name = managed_role_name(self) 419 role, created = Role.objects.get_or_create(name=name, managed=name) 420 if created: 421 role.users.add(self) 422 return role 423 else: 424 return Role.objects.filter(name=managed_role_name(self)).first()
465 def group_attributes(self, request: HttpRequest | None = None) -> dict[str, Any]: 466 """Get a dictionary containing the attributes from all groups the user belongs to, 467 including the users attributes""" 468 final_attributes = {} 469 if request and hasattr(request, "brand"): 470 always_merger.merge(final_attributes, request.brand.attributes) 471 for group in self.all_groups().order_by("name"): 472 always_merger.merge(final_attributes, group.attributes) 473 always_merger.merge(final_attributes, self.attributes) 474 return final_attributes
Get a dictionary containing the attributes from all groups the user belongs to, including the users attributes
476 def app_entitlements(self, app: Application | None) -> QuerySet[ApplicationEntitlement]: 477 """Get all entitlements this user has for `app`.""" 478 if not app: 479 return [] 480 all_groups = self.all_groups() 481 qs = app.applicationentitlement_set.filter( 482 Q( 483 Q(bindings__user=self) | Q(bindings__group__in=all_groups), 484 bindings__negate=False, 485 ) 486 | Q( 487 Q(~Q(bindings__user=self), bindings__user__isnull=False) 488 | Q(~Q(bindings__group__in=all_groups), bindings__group__isnull=False), 489 bindings__negate=True, 490 ), 491 bindings__enabled=True, 492 ).order_by("name") 493 return qs
Get all entitlements this user has for app.
495 def app_entitlements_attributes(self, app: Application | None) -> dict: 496 """Get a dictionary containing all merged attributes from app entitlements for `app`.""" 497 final_attributes = {} 498 for attrs in self.app_entitlements(app).values_list("attributes", flat=True): 499 always_merger.merge(final_attributes, attrs) 500 return final_attributes
Get a dictionary containing all merged attributes from app entitlements for app.
502 @property 503 def serializer(self) -> Serializer: 504 from authentik.core.api.users import UserSerializer 505 506 return UserSerializer
Get serializer for this model
Get supseruser status based on membership in a group with superuser status
513 @property 514 def is_staff(self) -> bool: 515 """superuser == staff user""" 516 return self.is_superuser # type: ignore
superuser == staff user
519 @property 520 def ak_groups(self): 521 """This is a proxy for a renamed, deprecated field.""" 522 from authentik.events.models import Event 523 524 deprecation = "authentik.core.models.User.ak_groups" 525 replacement = "authentik.core.models.User.groups" 526 message_logger = ( 527 f"{deprecation} is deprecated and will be removed in a future version of " 528 f"authentik. Please use {replacement} instead." 529 ) 530 message_event = ( 531 f"{message_logger} This event will not be repeated until it expires (by " 532 "default: in 30 days). See authentik logs for every will invocation of this " 533 "deprecation." 534 ) 535 stacktrace = traceback.format_stack() 536 # The last line is this function, the next-to-last line is its caller 537 cause = stacktrace[-2] if len(stacktrace) > 1 else "Unknown, see stacktrace in logs" 538 if search := re.search(r'"(.*?)"', cause): 539 cause = f"Property mapping or Expression policy named {search.group(1)}" 540 541 LOGGER.warning( 542 "deprecation used", 543 message=message_logger, 544 deprecation=deprecation, 545 replacement=replacement, 546 cause=cause, 547 stacktrace=stacktrace, 548 ) 549 Event.log_deprecation( 550 deprecation, message=message_event, cause=cause, replacement=replacement 551 ) 552 return self.groups
This is a proxy for a renamed, deprecated field.
554 def set_password(self, raw_password, signal=True, sender=None, request=None): 555 if self.pk and signal: 556 from authentik.core.signals import password_changed 557 558 if not sender: 559 sender = self 560 password_changed.send(sender=sender, user=self, password=raw_password, request=request) 561 self.password_change_date = now() 562 return super().set_password(raw_password)
564 @staticmethod 565 def validate_password_hash(password_hash: str): 566 """Validate that the value is a recognized Django password hash.""" 567 identify_hasher(password_hash) # Raises ValueError if invalid
Validate that the value is a recognized Django password hash.
569 def set_password_from_hash(self, password_hash: str, signal=True, sender=None, request=None): 570 """Set password directly from a pre-hashed value. 571 572 Unlike set_password(), this does not hash the input again. The provided value 573 must already be a valid Django password hash, and it is stored directly on the 574 user after validation. 575 576 Because no raw password is available, downstream password sync integrations 577 such as LDAP and Kerberos cannot be updated from this code path. 578 579 Raises ValueError if the hash format is not recognized. 580 """ 581 self.validate_password_hash(password_hash) 582 if self.pk and signal: 583 from authentik.core.signals import password_hash_changed 584 585 if not sender: 586 sender = self 587 password_hash_changed.send(sender=sender, user=self, request=request) 588 self.password = password_hash 589 self.password_change_date = now()
Set password directly from a pre-hashed value.
Unlike set_password(), this does not hash the input again. The provided value must already be a valid Django password hash, and it is stored directly on the user after validation.
Because no raw password is available, downstream password sync integrations such as LDAP and Kerberos cannot be updated from this code path.
Raises ValueError if the hash format is not recognized.
591 def check_password(self, raw_password: str) -> bool: 592 """ 593 Return a boolean of whether the raw_password was correct. Handles 594 hashing formats behind the scenes. 595 596 Slightly changed version which doesn't send a signal for such internal hash upgrades 597 """ 598 599 def setter(raw_password): 600 self.set_password(raw_password, signal=False) 601 # Password hash upgrades shouldn't be considered password changes. 602 self._password = None 603 self.save(update_fields=["password"]) 604 605 return check_password(raw_password, self.password, setter)
Return a boolean of whether the raw_password was correct. Handles hashing formats behind the scenes.
Slightly changed version which doesn't send a signal for such internal hash upgrades
607 @property 608 def uid(self) -> str: 609 """Generate a globally unique UID, based on the user ID and the hashed secret key""" 610 return sha256(f"{self.id}-{get_unique_identifier()}".encode("ascii")).hexdigest()
Generate a globally unique UID, based on the user ID and the hashed secret key
612 def locale(self, request: HttpRequest | None = None) -> str: 613 """Get the locale the user has configured""" 614 if request and hasattr(request, "LANGUAGE_CODE"): 615 return request.LANGUAGE_CODE 616 try: 617 return self.attributes.get("settings", {}).get("locale", "") 618 619 except Exception as exc: # noqa 620 LOGGER.warning("Failed to get default locale", exc=exc) 621 if request: 622 return request.brand.locale 623 return ""
Get the locale the user has configured
625 @property 626 def avatar(self) -> str: 627 """Get avatar, depending on authentik.avatar setting""" 628 return get_avatar(self)
Get avatar, depending on authentik.avatar setting
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.
In the example::
class Pizza(Model):
toppings = ManyToManyField(Topping, related_name='pizzas')
Pizza.toppings and Topping.pizzas are ManyToManyDescriptor
instances.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Parent.children is a ReverseManyToOneDescriptor instance.
Most of the implementation is delegated to a dynamically defined manager
class built by create_forward_many_to_many_manager() defined below.
The requested object does not exist
The query returned multiple objects when only one was expected.
Send SAML LogoutRequest to a Service Provider using session data
58def send_post_logout_request(provider: SAMLProvider, processor: LogoutRequestProcessor) -> bool: 59 """Send LogoutRequest using POST binding""" 60 encoded_request = processor.encode_post() 61 62 form_data = { 63 "SAMLRequest": encoded_request, 64 } 65 66 if processor.relay_state: 67 form_data["RelayState"] = processor.relay_state 68 69 response = requests.post( 70 provider.sls_url, 71 data=form_data, 72 timeout=10, 73 headers={ 74 "Content-Type": "application/x-www-form-urlencoded", 75 }, 76 allow_redirects=True, 77 ) 78 response.raise_for_status() 79 80 LOGGER.debug( 81 "Sent POST logout request", 82 provider=provider, 83 status_code=response.status_code, 84 ) 85 86 return True
Send LogoutRequest using POST binding
Send SAML LogoutResponse to a Service Provider using backchannel (server-to-server)