authentik.sources.saml.models
saml sp models
1"""saml sp models""" 2 3from typing import Any 4 5from django.db import models 6from django.http import HttpRequest 7from django.templatetags.static import static 8from django.urls import reverse 9from django.utils.translation import gettext_lazy as _ 10from lxml.etree import _Element # nosec 11from rest_framework.serializers import Serializer 12 13from authentik.common.saml.constants import ( 14 DSA_SHA1, 15 ECDSA_SHA1, 16 ECDSA_SHA256, 17 ECDSA_SHA384, 18 ECDSA_SHA512, 19 NS_SAML_ASSERTION, 20 RSA_SHA1, 21 RSA_SHA256, 22 RSA_SHA384, 23 RSA_SHA512, 24 SAML_ATTRIBUTES_GROUP, 25 SAML_BINDING_POST, 26 SAML_BINDING_REDIRECT, 27 SAML_NAME_ID_FORMAT_EMAIL, 28 SAML_NAME_ID_FORMAT_PERSISTENT, 29 SAML_NAME_ID_FORMAT_TRANSIENT, 30 SAML_NAME_ID_FORMAT_UNSPECIFIED, 31 SAML_NAME_ID_FORMAT_WINDOWS, 32 SAML_NAME_ID_FORMAT_X509, 33 SHA1, 34 SHA256, 35 SHA384, 36 SHA512, 37) 38from authentik.core.models import ( 39 GroupSourceConnection, 40 PropertyMapping, 41 Source, 42 UserSourceConnection, 43) 44from authentik.core.types import UILoginButton, UserSettingSerializer 45from authentik.crypto.models import CertificateKeyPair 46from authentik.flows.challenge import RedirectChallenge 47from authentik.flows.models import Flow 48from authentik.lib.expression.evaluator import BaseEvaluator 49from authentik.lib.models import DomainlessURLValidator 50from authentik.lib.utils.time import timedelta_string_validator 51 52 53class SAMLBindingTypes(models.TextChoices): 54 """SAML Binding types""" 55 56 REDIRECT = "REDIRECT", _("Redirect Binding") 57 POST = "POST", _("POST Binding") 58 POST_AUTO = "POST_AUTO", _("POST Binding with auto-confirmation") 59 60 @property 61 def uri(self) -> str: 62 """Convert database field to URI""" 63 return { 64 SAMLBindingTypes.POST: SAML_BINDING_POST, 65 SAMLBindingTypes.POST_AUTO: SAML_BINDING_POST, 66 SAMLBindingTypes.REDIRECT: SAML_BINDING_REDIRECT, 67 }[self] 68 69 70class SAMLNameIDPolicy(models.TextChoices): 71 """SAML NameID Policies""" 72 73 EMAIL = SAML_NAME_ID_FORMAT_EMAIL 74 PERSISTENT = SAML_NAME_ID_FORMAT_PERSISTENT 75 X509 = SAML_NAME_ID_FORMAT_X509 76 WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS 77 TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT 78 UNSPECIFIED = SAML_NAME_ID_FORMAT_UNSPECIFIED 79 80 81class SAMLSource(Source): 82 """Authenticate using an external SAML Identity Provider.""" 83 84 pre_authentication_flow = models.ForeignKey( 85 Flow, 86 on_delete=models.CASCADE, 87 help_text=_("Flow used before authentication."), 88 related_name="source_pre_authentication", 89 ) 90 91 issuer = models.TextField( 92 blank=True, 93 default=None, 94 verbose_name=_("Issuer"), 95 help_text=_("Also known as Entity ID. Defaults the Metadata URL."), 96 ) 97 98 sso_url = models.TextField( 99 validators=[DomainlessURLValidator(schemes=("http", "https"))], 100 verbose_name=_("SSO URL"), 101 help_text=_("URL that the initial Login request is sent to."), 102 ) 103 slo_url = models.TextField( 104 validators=[DomainlessURLValidator(schemes=("http", "https"))], 105 default=None, 106 blank=True, 107 null=True, 108 verbose_name=_("SLO URL"), 109 help_text=_("Optional URL if your IDP supports Single-Logout."), 110 ) 111 112 allow_idp_initiated = models.BooleanField( 113 default=False, 114 help_text=_( 115 "Allows authentication flows initiated by the IdP. This can be a security risk, " 116 "as no validation of the request ID is done." 117 ), 118 ) 119 force_authn = models.BooleanField( 120 default=False, 121 help_text=_( 122 "When enabled, the IdP will re-authenticate the user even if a session exists." 123 ), 124 ) 125 name_id_policy = models.TextField( 126 choices=SAMLNameIDPolicy.choices, 127 default=SAMLNameIDPolicy.PERSISTENT, 128 help_text=_( 129 "NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent." 130 ), 131 ) 132 binding_type = models.CharField( 133 max_length=100, 134 choices=SAMLBindingTypes.choices, 135 default=SAMLBindingTypes.REDIRECT, 136 ) 137 138 temporary_user_delete_after = models.TextField( 139 default="days=1", 140 verbose_name=_("Delete temporary users after"), 141 validators=[timedelta_string_validator], 142 help_text=_( 143 "Time offset when temporary users should be deleted. This only applies if your IDP " 144 "uses the NameID Format 'transient', and the user doesn't log out manually. " 145 "(Format: hours=1;minutes=2;seconds=3)." 146 ), 147 ) 148 149 verification_kp = models.ForeignKey( 150 CertificateKeyPair, 151 default=None, 152 null=True, 153 blank=True, 154 help_text=_( 155 "When selected, incoming assertion's Signatures will be validated against this " 156 "certificate. To allow unsigned Requests, leave on default." 157 ), 158 on_delete=models.SET_NULL, 159 verbose_name=_("Verification Certificate"), 160 related_name="+", 161 ) 162 signing_kp = models.ForeignKey( 163 CertificateKeyPair, 164 default=None, 165 null=True, 166 blank=True, 167 help_text=_("Keypair used to sign outgoing Responses going to the Identity Provider."), 168 on_delete=models.SET_NULL, 169 verbose_name=_("Signing Keypair"), 170 ) 171 encryption_kp = models.ForeignKey( 172 CertificateKeyPair, 173 default=None, 174 null=True, 175 blank=True, 176 help_text=_( 177 "When selected, incoming assertions are encrypted by the IdP using the public " 178 "key of the encryption keypair. The assertion is decrypted by the SP using the " 179 "the private key." 180 ), 181 on_delete=models.SET_NULL, 182 verbose_name=_("Encryption Keypair"), 183 related_name="+", 184 ) 185 186 digest_algorithm = models.TextField( 187 choices=( 188 (SHA1, _("SHA1")), 189 (SHA256, _("SHA256")), 190 (SHA384, _("SHA384")), 191 (SHA512, _("SHA512")), 192 ), 193 default=SHA256, 194 ) 195 signature_algorithm = models.TextField( 196 choices=( 197 (RSA_SHA1, _("RSA-SHA1")), 198 (RSA_SHA256, _("RSA-SHA256")), 199 (RSA_SHA384, _("RSA-SHA384")), 200 (RSA_SHA512, _("RSA-SHA512")), 201 (ECDSA_SHA1, _("ECDSA-SHA1")), 202 (ECDSA_SHA256, _("ECDSA-SHA256")), 203 (ECDSA_SHA384, _("ECDSA-SHA384")), 204 (ECDSA_SHA512, _("ECDSA-SHA512")), 205 (DSA_SHA1, _("DSA-SHA1")), 206 ), 207 default=RSA_SHA256, 208 ) 209 210 signed_assertion = models.BooleanField(default=True) 211 signed_response = models.BooleanField(default=False) 212 213 @property 214 def component(self) -> str: 215 return "ak-source-saml-form" 216 217 @property 218 def serializer(self) -> type[Serializer]: 219 from authentik.sources.saml.api.source import SAMLSourceSerializer 220 221 return SAMLSourceSerializer 222 223 @property 224 def property_mapping_type(self) -> type[PropertyMapping]: 225 return SAMLSourcePropertyMapping 226 227 def get_base_user_properties(self, root: _Element, assertion: _Element, name_id: Any, **kwargs): 228 attributes = {} 229 if assertion is None: 230 raise ValueError("Assertion element not found") 231 attribute_statement = assertion.find(f"{{{NS_SAML_ASSERTION}}}AttributeStatement") 232 if attribute_statement is None: 233 raise ValueError("Attribute statement element not found") 234 # Get all attributes and their values into a dict 235 for attribute in attribute_statement.iterchildren(): 236 key = attribute.attrib["Name"] 237 attributes.setdefault(key, []) 238 for value in attribute.iterchildren(): 239 attributes[key].append(value.text) 240 if SAML_ATTRIBUTES_GROUP in attributes: 241 attributes["groups"] = attributes[SAML_ATTRIBUTES_GROUP] 242 del attributes[SAML_ATTRIBUTES_GROUP] 243 # Flatten all lists in the dict 244 for key, value in attributes.items(): 245 if key == "groups": 246 continue 247 attributes[key] = BaseEvaluator.expr_flatten(value) 248 attributes["username"] = name_id.text 249 250 return attributes 251 252 def get_base_group_properties(self, group_id: str, **kwargs): 253 return { 254 "name": group_id, 255 } 256 257 def get_issuer(self, request: HttpRequest) -> str: 258 """Get Source's Issuer, falling back to our Metadata URL if none is set""" 259 if self.issuer is None: 260 return self.build_full_url(request, view="metadata") 261 return self.issuer 262 263 def build_full_url(self, request: HttpRequest, view: str = "acs") -> str: 264 """Build Full ACS URL to be used in IDP""" 265 return request.build_absolute_uri( 266 reverse(f"authentik_sources_saml:{view}", kwargs={"source_slug": self.slug}) 267 ) 268 269 @property 270 def icon_url(self) -> str: 271 icon = super().icon_url 272 if not icon: 273 return static("authentik/sources/saml.png") 274 return icon 275 276 def ui_login_button(self, request: HttpRequest) -> UILoginButton: 277 return UILoginButton( 278 challenge=RedirectChallenge( 279 data={ 280 "to": reverse( 281 "authentik_sources_saml:login", 282 kwargs={"source_slug": self.slug}, 283 ), 284 } 285 ), 286 name=self.name, 287 icon_url=self.icon_url, 288 promoted=self.promoted, 289 ) 290 291 def ui_user_settings(self) -> UserSettingSerializer | None: 292 return UserSettingSerializer( 293 data={ 294 "title": self.name, 295 "component": "ak-user-settings-source-saml", 296 "configure_url": reverse( 297 "authentik_sources_saml:login", 298 kwargs={"source_slug": self.slug}, 299 ), 300 "icon_url": self.icon_url, 301 } 302 ) 303 304 def __str__(self): 305 return f"SAML Source {self.name}" 306 307 class Meta: 308 verbose_name = _("SAML Source") 309 verbose_name_plural = _("SAML Sources") 310 311 312class SAMLSourcePropertyMapping(PropertyMapping): 313 """Map SAML properties to User or Group object attributes""" 314 315 @property 316 def component(self) -> str: 317 return "ak-property-mapping-source-saml-form" 318 319 @property 320 def serializer(self) -> type[Serializer]: 321 from authentik.sources.saml.api.property_mappings import SAMLSourcePropertyMappingSerializer 322 323 return SAMLSourcePropertyMappingSerializer 324 325 class Meta: 326 verbose_name = _("SAML Source Property Mapping") 327 verbose_name_plural = _("SAML Source Property Mappings") 328 329 330class UserSAMLSourceConnection(UserSourceConnection): 331 """Connection to configured SAML Sources.""" 332 333 @property 334 def serializer(self) -> Serializer: 335 from authentik.sources.saml.api.source_connection import UserSAMLSourceConnectionSerializer 336 337 return UserSAMLSourceConnectionSerializer 338 339 class Meta: 340 verbose_name = _("User SAML Source Connection") 341 verbose_name_plural = _("User SAML Source Connections") 342 343 344class GroupSAMLSourceConnection(GroupSourceConnection): 345 """Group-source connection""" 346 347 @property 348 def serializer(self) -> type[Serializer]: 349 from authentik.sources.saml.api.source_connection import ( 350 GroupSAMLSourceConnectionSerializer, 351 ) 352 353 return GroupSAMLSourceConnectionSerializer 354 355 class Meta: 356 verbose_name = _("Group SAML Source Connection") 357 verbose_name_plural = _("Group SAML Source Connections")
54class SAMLBindingTypes(models.TextChoices): 55 """SAML Binding types""" 56 57 REDIRECT = "REDIRECT", _("Redirect Binding") 58 POST = "POST", _("POST Binding") 59 POST_AUTO = "POST_AUTO", _("POST Binding with auto-confirmation") 60 61 @property 62 def uri(self) -> str: 63 """Convert database field to URI""" 64 return { 65 SAMLBindingTypes.POST: SAML_BINDING_POST, 66 SAMLBindingTypes.POST_AUTO: SAML_BINDING_POST, 67 SAMLBindingTypes.REDIRECT: SAML_BINDING_REDIRECT, 68 }[self]
SAML Binding types
71class SAMLNameIDPolicy(models.TextChoices): 72 """SAML NameID Policies""" 73 74 EMAIL = SAML_NAME_ID_FORMAT_EMAIL 75 PERSISTENT = SAML_NAME_ID_FORMAT_PERSISTENT 76 X509 = SAML_NAME_ID_FORMAT_X509 77 WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS 78 TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT 79 UNSPECIFIED = SAML_NAME_ID_FORMAT_UNSPECIFIED
SAML NameID Policies
82class SAMLSource(Source): 83 """Authenticate using an external SAML Identity Provider.""" 84 85 pre_authentication_flow = models.ForeignKey( 86 Flow, 87 on_delete=models.CASCADE, 88 help_text=_("Flow used before authentication."), 89 related_name="source_pre_authentication", 90 ) 91 92 issuer = models.TextField( 93 blank=True, 94 default=None, 95 verbose_name=_("Issuer"), 96 help_text=_("Also known as Entity ID. Defaults the Metadata URL."), 97 ) 98 99 sso_url = models.TextField( 100 validators=[DomainlessURLValidator(schemes=("http", "https"))], 101 verbose_name=_("SSO URL"), 102 help_text=_("URL that the initial Login request is sent to."), 103 ) 104 slo_url = models.TextField( 105 validators=[DomainlessURLValidator(schemes=("http", "https"))], 106 default=None, 107 blank=True, 108 null=True, 109 verbose_name=_("SLO URL"), 110 help_text=_("Optional URL if your IDP supports Single-Logout."), 111 ) 112 113 allow_idp_initiated = models.BooleanField( 114 default=False, 115 help_text=_( 116 "Allows authentication flows initiated by the IdP. This can be a security risk, " 117 "as no validation of the request ID is done." 118 ), 119 ) 120 force_authn = models.BooleanField( 121 default=False, 122 help_text=_( 123 "When enabled, the IdP will re-authenticate the user even if a session exists." 124 ), 125 ) 126 name_id_policy = models.TextField( 127 choices=SAMLNameIDPolicy.choices, 128 default=SAMLNameIDPolicy.PERSISTENT, 129 help_text=_( 130 "NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent." 131 ), 132 ) 133 binding_type = models.CharField( 134 max_length=100, 135 choices=SAMLBindingTypes.choices, 136 default=SAMLBindingTypes.REDIRECT, 137 ) 138 139 temporary_user_delete_after = models.TextField( 140 default="days=1", 141 verbose_name=_("Delete temporary users after"), 142 validators=[timedelta_string_validator], 143 help_text=_( 144 "Time offset when temporary users should be deleted. This only applies if your IDP " 145 "uses the NameID Format 'transient', and the user doesn't log out manually. " 146 "(Format: hours=1;minutes=2;seconds=3)." 147 ), 148 ) 149 150 verification_kp = models.ForeignKey( 151 CertificateKeyPair, 152 default=None, 153 null=True, 154 blank=True, 155 help_text=_( 156 "When selected, incoming assertion's Signatures will be validated against this " 157 "certificate. To allow unsigned Requests, leave on default." 158 ), 159 on_delete=models.SET_NULL, 160 verbose_name=_("Verification Certificate"), 161 related_name="+", 162 ) 163 signing_kp = models.ForeignKey( 164 CertificateKeyPair, 165 default=None, 166 null=True, 167 blank=True, 168 help_text=_("Keypair used to sign outgoing Responses going to the Identity Provider."), 169 on_delete=models.SET_NULL, 170 verbose_name=_("Signing Keypair"), 171 ) 172 encryption_kp = models.ForeignKey( 173 CertificateKeyPair, 174 default=None, 175 null=True, 176 blank=True, 177 help_text=_( 178 "When selected, incoming assertions are encrypted by the IdP using the public " 179 "key of the encryption keypair. The assertion is decrypted by the SP using the " 180 "the private key." 181 ), 182 on_delete=models.SET_NULL, 183 verbose_name=_("Encryption Keypair"), 184 related_name="+", 185 ) 186 187 digest_algorithm = models.TextField( 188 choices=( 189 (SHA1, _("SHA1")), 190 (SHA256, _("SHA256")), 191 (SHA384, _("SHA384")), 192 (SHA512, _("SHA512")), 193 ), 194 default=SHA256, 195 ) 196 signature_algorithm = models.TextField( 197 choices=( 198 (RSA_SHA1, _("RSA-SHA1")), 199 (RSA_SHA256, _("RSA-SHA256")), 200 (RSA_SHA384, _("RSA-SHA384")), 201 (RSA_SHA512, _("RSA-SHA512")), 202 (ECDSA_SHA1, _("ECDSA-SHA1")), 203 (ECDSA_SHA256, _("ECDSA-SHA256")), 204 (ECDSA_SHA384, _("ECDSA-SHA384")), 205 (ECDSA_SHA512, _("ECDSA-SHA512")), 206 (DSA_SHA1, _("DSA-SHA1")), 207 ), 208 default=RSA_SHA256, 209 ) 210 211 signed_assertion = models.BooleanField(default=True) 212 signed_response = models.BooleanField(default=False) 213 214 @property 215 def component(self) -> str: 216 return "ak-source-saml-form" 217 218 @property 219 def serializer(self) -> type[Serializer]: 220 from authentik.sources.saml.api.source import SAMLSourceSerializer 221 222 return SAMLSourceSerializer 223 224 @property 225 def property_mapping_type(self) -> type[PropertyMapping]: 226 return SAMLSourcePropertyMapping 227 228 def get_base_user_properties(self, root: _Element, assertion: _Element, name_id: Any, **kwargs): 229 attributes = {} 230 if assertion is None: 231 raise ValueError("Assertion element not found") 232 attribute_statement = assertion.find(f"{{{NS_SAML_ASSERTION}}}AttributeStatement") 233 if attribute_statement is None: 234 raise ValueError("Attribute statement element not found") 235 # Get all attributes and their values into a dict 236 for attribute in attribute_statement.iterchildren(): 237 key = attribute.attrib["Name"] 238 attributes.setdefault(key, []) 239 for value in attribute.iterchildren(): 240 attributes[key].append(value.text) 241 if SAML_ATTRIBUTES_GROUP in attributes: 242 attributes["groups"] = attributes[SAML_ATTRIBUTES_GROUP] 243 del attributes[SAML_ATTRIBUTES_GROUP] 244 # Flatten all lists in the dict 245 for key, value in attributes.items(): 246 if key == "groups": 247 continue 248 attributes[key] = BaseEvaluator.expr_flatten(value) 249 attributes["username"] = name_id.text 250 251 return attributes 252 253 def get_base_group_properties(self, group_id: str, **kwargs): 254 return { 255 "name": group_id, 256 } 257 258 def get_issuer(self, request: HttpRequest) -> str: 259 """Get Source's Issuer, falling back to our Metadata URL if none is set""" 260 if self.issuer is None: 261 return self.build_full_url(request, view="metadata") 262 return self.issuer 263 264 def build_full_url(self, request: HttpRequest, view: str = "acs") -> str: 265 """Build Full ACS URL to be used in IDP""" 266 return request.build_absolute_uri( 267 reverse(f"authentik_sources_saml:{view}", kwargs={"source_slug": self.slug}) 268 ) 269 270 @property 271 def icon_url(self) -> str: 272 icon = super().icon_url 273 if not icon: 274 return static("authentik/sources/saml.png") 275 return icon 276 277 def ui_login_button(self, request: HttpRequest) -> UILoginButton: 278 return UILoginButton( 279 challenge=RedirectChallenge( 280 data={ 281 "to": reverse( 282 "authentik_sources_saml:login", 283 kwargs={"source_slug": self.slug}, 284 ), 285 } 286 ), 287 name=self.name, 288 icon_url=self.icon_url, 289 promoted=self.promoted, 290 ) 291 292 def ui_user_settings(self) -> UserSettingSerializer | None: 293 return UserSettingSerializer( 294 data={ 295 "title": self.name, 296 "component": "ak-user-settings-source-saml", 297 "configure_url": reverse( 298 "authentik_sources_saml:login", 299 kwargs={"source_slug": self.slug}, 300 ), 301 "icon_url": self.icon_url, 302 } 303 ) 304 305 def __str__(self): 306 return f"SAML Source {self.name}" 307 308 class Meta: 309 verbose_name = _("SAML Source") 310 verbose_name_plural = _("SAML Sources")
Authenticate using an external SAML Identity Provider.
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Child.parent is a ForwardManyToOneDescriptor instance.
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.
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Child.parent is a ForwardManyToOneDescriptor instance.
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Child.parent is a ForwardManyToOneDescriptor instance.
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example::
class Child(Model):
parent = ForeignKey(Parent, related_name='children')
Child.parent is a ForwardManyToOneDescriptor instance.
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.
218 @property 219 def serializer(self) -> type[Serializer]: 220 from authentik.sources.saml.api.source import SAMLSourceSerializer 221 222 return SAMLSourceSerializer
Get serializer for this model
224 @property 225 def property_mapping_type(self) -> type[PropertyMapping]: 226 return SAMLSourcePropertyMapping
Return property mapping type used by this object
228 def get_base_user_properties(self, root: _Element, assertion: _Element, name_id: Any, **kwargs): 229 attributes = {} 230 if assertion is None: 231 raise ValueError("Assertion element not found") 232 attribute_statement = assertion.find(f"{{{NS_SAML_ASSERTION}}}AttributeStatement") 233 if attribute_statement is None: 234 raise ValueError("Attribute statement element not found") 235 # Get all attributes and their values into a dict 236 for attribute in attribute_statement.iterchildren(): 237 key = attribute.attrib["Name"] 238 attributes.setdefault(key, []) 239 for value in attribute.iterchildren(): 240 attributes[key].append(value.text) 241 if SAML_ATTRIBUTES_GROUP in attributes: 242 attributes["groups"] = attributes[SAML_ATTRIBUTES_GROUP] 243 del attributes[SAML_ATTRIBUTES_GROUP] 244 # Flatten all lists in the dict 245 for key, value in attributes.items(): 246 if key == "groups": 247 continue 248 attributes[key] = BaseEvaluator.expr_flatten(value) 249 attributes["username"] = name_id.text 250 251 return attributes
Get base properties for a user to build final properties upon.
253 def get_base_group_properties(self, group_id: str, **kwargs): 254 return { 255 "name": group_id, 256 }
Get base properties for a group to build final properties upon.
258 def get_issuer(self, request: HttpRequest) -> str: 259 """Get Source's Issuer, falling back to our Metadata URL if none is set""" 260 if self.issuer is None: 261 return self.build_full_url(request, view="metadata") 262 return self.issuer
Get Source's Issuer, falling back to our Metadata URL if none is set
264 def build_full_url(self, request: HttpRequest, view: str = "acs") -> str: 265 """Build Full ACS URL to be used in IDP""" 266 return request.build_absolute_uri( 267 reverse(f"authentik_sources_saml:{view}", kwargs={"source_slug": self.slug}) 268 )
Build Full ACS URL to be used in IDP
270 @property 271 def icon_url(self) -> str: 272 icon = super().icon_url 273 if not icon: 274 return static("authentik/sources/saml.png") 275 return icon
Get the URL to the source icon
292 def ui_user_settings(self) -> UserSettingSerializer | None: 293 return UserSettingSerializer( 294 data={ 295 "title": self.name, 296 "component": "ak-user-settings-source-saml", 297 "configure_url": reverse( 298 "authentik_sources_saml:login", 299 kwargs={"source_slug": self.slug}, 300 ), 301 "icon_url": self.icon_url, 302 } 303 )
Entrypoint to integrate with User settings. Can either return None if no user settings are available, or UserSettingSerializer.
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.
Accessor to the related object on the forward side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Restaurant.place is a ForwardOneToOneDescriptor instance.
Inherited Members
- authentik.core.models.Source
- MANAGED_INBUILT
- name
- slug
- user_path_template
- enabled
- promoted
- user_property_mappings
- group_property_mappings
- icon
- authentication_flow
- enrollment_flow
- user_matching_mode
- group_matching_mode
- objects
- icon_themed_urls
- get_user_path
- managed
- authentication_flow_id
- enrollment_flow_id
- get_user_matching_mode_display
- get_group_matching_mode_display
- policybindingmodel_ptr_id
- policybindingmodel_ptr
- user_set
- usersourceconnection_set
- groupsourceconnection_set
- oauthsource
- samlsource
- kerberossource
- ldapsource
- identificationstage_set
- plexsource
- scimsource
- telegramsource
- sourcestage_set
The requested object does not exist
The query returned multiple objects when only one was expected.
313class SAMLSourcePropertyMapping(PropertyMapping): 314 """Map SAML properties to User or Group object attributes""" 315 316 @property 317 def component(self) -> str: 318 return "ak-property-mapping-source-saml-form" 319 320 @property 321 def serializer(self) -> type[Serializer]: 322 from authentik.sources.saml.api.property_mappings import SAMLSourcePropertyMappingSerializer 323 324 return SAMLSourcePropertyMappingSerializer 325 326 class Meta: 327 verbose_name = _("SAML Source Property Mapping") 328 verbose_name_plural = _("SAML Source Property Mappings")
Map SAML properties to User or Group object attributes
320 @property 321 def serializer(self) -> type[Serializer]: 322 from authentik.sources.saml.api.property_mappings import SAMLSourcePropertyMappingSerializer 323 324 return SAMLSourcePropertyMappingSerializer
Get serializer for this model
Accessor to the related object on the forward side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Restaurant.place is a ForwardOneToOneDescriptor instance.
Inherited Members
- authentik.core.models.PropertyMapping
- pm_uuid
- name
- expression
- objects
- evaluate
- managed
- provider_set
- source_userpropertymappings_set
- source_grouppropertymappings_set
- notificationwebhookmapping
- oauthsourcepropertymapping
- scopemapping
- endpoint_set
- racpropertymapping
- radiusproviderpropertymapping
- samlsourcepropertymapping
- samlpropertymapping
- scimprovider_set
- scimmapping
- kerberossourcepropertymapping
- ldapsourcepropertymapping
- plexsourcepropertymapping
- scimsourcepropertymapping
- telegramsourcepropertymapping
- googleworkspaceprovider_set
- googleworkspaceprovidermapping
- microsoftentraprovider_set
- microsoftentraprovidermapping
The requested object does not exist
The query returned multiple objects when only one was expected.
331class UserSAMLSourceConnection(UserSourceConnection): 332 """Connection to configured SAML Sources.""" 333 334 @property 335 def serializer(self) -> Serializer: 336 from authentik.sources.saml.api.source_connection import UserSAMLSourceConnectionSerializer 337 338 return UserSAMLSourceConnectionSerializer 339 340 class Meta: 341 verbose_name = _("User SAML Source Connection") 342 verbose_name_plural = _("User SAML Source Connections")
Connection to configured SAML Sources.
334 @property 335 def serializer(self) -> Serializer: 336 from authentik.sources.saml.api.source_connection import UserSAMLSourceConnectionSerializer 337 338 return UserSAMLSourceConnectionSerializer
Get serializer for this model
Accessor to the related object on the forward side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Restaurant.place is a ForwardOneToOneDescriptor instance.
Inherited Members
- authentik.core.models.UserSourceConnection
- user
- source
- identifier
- objects
- created
- last_updated
- user_id
- source_id
- get_next_by_created
- get_previous_by_created
- get_next_by_last_updated
- get_previous_by_last_updated
- id
- useroauthsourceconnection
- usersamlsourceconnection
- userkerberossourceconnection
- userldapsourceconnection
- userplexsourceconnection
- usertelegramsourceconnection
The requested object does not exist
The query returned multiple objects when only one was expected.
345class GroupSAMLSourceConnection(GroupSourceConnection): 346 """Group-source connection""" 347 348 @property 349 def serializer(self) -> type[Serializer]: 350 from authentik.sources.saml.api.source_connection import ( 351 GroupSAMLSourceConnectionSerializer, 352 ) 353 354 return GroupSAMLSourceConnectionSerializer 355 356 class Meta: 357 verbose_name = _("Group SAML Source Connection") 358 verbose_name_plural = _("Group SAML Source Connections")
Group-source connection
348 @property 349 def serializer(self) -> type[Serializer]: 350 from authentik.sources.saml.api.source_connection import ( 351 GroupSAMLSourceConnectionSerializer, 352 ) 353 354 return GroupSAMLSourceConnectionSerializer
Get serializer for this model
Accessor to the related object on the forward side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Restaurant.place is a ForwardOneToOneDescriptor instance.
Inherited Members
- authentik.core.models.GroupSourceConnection
- group
- source
- identifier
- objects
- created
- last_updated
- group_id
- source_id
- get_next_by_created
- get_previous_by_created
- get_next_by_last_updated
- get_previous_by_last_updated
- id
- groupoauthsourceconnection
- groupsamlsourceconnection
- groupkerberossourceconnection
- groupldapsourceconnection
- groupplexsourceconnection
- grouptelegramsourceconnection
The requested object does not exist
The query returned multiple objects when only one was expected.