authentik.providers.proxy.models
authentik proxy models
1"""authentik proxy models""" 2 3import string 4from collections.abc import Iterable 5from random import SystemRandom 6from urllib.parse import urljoin 7from uuid import uuid4 8 9from django.db import models 10from django.templatetags.static import static 11from django.utils.translation import gettext as _ 12from rest_framework.serializers import Serializer 13 14from authentik.core.models import ExpiringModel 15from authentik.crypto.models import CertificateKeyPair 16from authentik.lib.models import DomainlessURLValidator, InternallyManagedMixin 17from authentik.outposts.models import OutpostModel 18from authentik.providers.oauth2.models import ( 19 ClientTypes, 20 OAuth2Provider, 21 RedirectURI, 22 RedirectURIMatchingMode, 23 ScopeMapping, 24) 25 26SCOPE_AK_PROXY = "ak_proxy" 27OUTPOST_CALLBACK_SIGNATURE = "X-authentik-auth-callback" 28 29 30class ProxySession(InternallyManagedMixin, ExpiringModel): 31 """Session storage for proxyv2 outposts using PostgreSQL""" 32 33 uuid = models.UUIDField(default=uuid4, primary_key=True) 34 session_key = models.TextField(unique=True, db_index=True) 35 user_id = models.UUIDField(null=True, blank=True, db_index=True) 36 37 session_data = models.JSONField(default=dict, blank=True) 38 39 class Meta: 40 verbose_name = _("Proxy Session") 41 verbose_name_plural = _("Proxy Sessions") 42 indexes = [ 43 models.Index(fields=["user_id"]), 44 ] 45 46 def __str__(self) -> str: 47 return f"Session {self.session_key[:8]}..." 48 49 50def get_cookie_secret(): 51 """Generate random 32-character string for cookie-secret""" 52 return "".join(SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(32)) 53 54 55def _get_callback_url(uri: str) -> list[RedirectURI]: 56 return [ 57 RedirectURI( 58 RedirectURIMatchingMode.STRICT, 59 urljoin(uri, "outpost.goauthentik.io/callback") + f"?{OUTPOST_CALLBACK_SIGNATURE}=true", 60 ), 61 RedirectURI(RedirectURIMatchingMode.STRICT, uri + f"?{OUTPOST_CALLBACK_SIGNATURE}=true"), 62 ] 63 64 65class ProxyMode(models.TextChoices): 66 """All modes a Proxy provider can operate in""" 67 68 PROXY = "proxy" 69 FORWARD_SINGLE = "forward_single" 70 FORWARD_DOMAIN = "forward_domain" 71 72 73class ProxyProvider(OutpostModel, OAuth2Provider): 74 """Protect applications that don't support any of the other 75 Protocols by using a Reverse-Proxy.""" 76 77 internal_host = models.TextField( 78 validators=[DomainlessURLValidator(schemes=("http", "https"))], 79 blank=True, 80 ) 81 external_host = models.TextField(validators=[DomainlessURLValidator(schemes=("http", "https"))]) 82 internal_host_ssl_validation = models.BooleanField( 83 default=True, 84 help_text=_("Validate SSL Certificates of upstream servers"), 85 verbose_name=_("Internal host SSL Validation"), 86 ) 87 mode = models.TextField( 88 default=ProxyMode.PROXY, 89 choices=ProxyMode.choices, 90 help_text=_( 91 "Enable support for forwardAuth in traefik and nginx auth_request. Exclusive with " 92 "internal_host." 93 ), 94 ) 95 96 skip_path_regex = models.TextField( 97 default="", 98 blank=True, 99 help_text=_( 100 "Regular expressions for which authentication is not required. " 101 "Each new line is interpreted as a new Regular Expression." 102 ), 103 ) 104 105 intercept_header_auth = models.BooleanField( 106 default=True, 107 help_text=_( 108 "When enabled, this provider will intercept the authorization header and authenticate " 109 "requests based on its value." 110 ), 111 ) 112 basic_auth_enabled = models.BooleanField( 113 default=False, 114 verbose_name=_("Set HTTP-Basic Authentication"), 115 help_text=_( 116 "Set a custom HTTP-Basic Authentication header based on values from authentik." 117 ), 118 ) 119 basic_auth_user_attribute = models.TextField( 120 blank=True, 121 verbose_name=_("HTTP-Basic Username Key"), 122 help_text=_( 123 "User/Group Attribute used for the user part of the HTTP-Basic Header. " 124 "If not set, the user's Email address is used." 125 ), 126 ) 127 basic_auth_password_attribute = models.TextField( 128 blank=True, 129 verbose_name=_("HTTP-Basic Password Key"), 130 help_text=_("User/Group Attribute used for the password part of the HTTP-Basic Header."), 131 ) 132 133 certificate = models.ForeignKey( 134 CertificateKeyPair, 135 on_delete=models.SET_NULL, 136 null=True, 137 blank=True, 138 ) 139 140 cookie_secret = models.TextField(default=get_cookie_secret) 141 cookie_domain = models.TextField(default="", blank=True) 142 143 @property 144 def component(self) -> str: 145 return "ak-provider-proxy-form" 146 147 @property 148 def icon_url(self) -> str | None: 149 return static("authentik/sources/proxy.svg") 150 151 @property 152 def serializer(self) -> type[Serializer]: 153 from authentik.providers.proxy.api import ProxyProviderSerializer 154 155 return ProxyProviderSerializer 156 157 @property 158 def launch_url(self) -> str | None: 159 """Use external_host as launch URL""" 160 return self.external_host 161 162 def set_oauth_defaults(self): 163 """Ensure all OAuth2-related settings are correct""" 164 self.client_type = ClientTypes.CONFIDENTIAL 165 self.signing_key = None 166 self.include_claims_in_id_token = True 167 scopes = ScopeMapping.objects.filter( 168 managed__in=[ 169 "goauthentik.io/providers/oauth2/scope-openid", 170 "goauthentik.io/providers/oauth2/scope-profile", 171 "goauthentik.io/providers/oauth2/scope-email", 172 "goauthentik.io/providers/oauth2/scope-entitlements", 173 "goauthentik.io/providers/proxy/scope-proxy", 174 ] 175 ) 176 self.property_mappings.add(*list(scopes)) 177 self.redirect_uris = _get_callback_url(self.external_host) 178 179 def __str__(self): 180 return f"Proxy Provider {self.name}" 181 182 def get_required_objects(self) -> Iterable[models.Model | str | tuple[str, models.Model]]: 183 required = [self] 184 if self.certificate is not None: 185 required.append(("authentik_crypto.view_certificatekeypair", self.certificate)) 186 required.append( 187 ("authentik_crypto.view_certificatekeypair_certificate", self.certificate) 188 ) 189 required.append(("authentik_crypto.view_certificatekeypair_key", self.certificate)) 190 return required 191 192 class Meta: 193 verbose_name = _("Proxy Provider") 194 verbose_name_plural = _("Proxy Providers") 195 authentik_used_by_shadows = ["authentik_providers_oauth2.oauth2provider"]
31class ProxySession(InternallyManagedMixin, ExpiringModel): 32 """Session storage for proxyv2 outposts using PostgreSQL""" 33 34 uuid = models.UUIDField(default=uuid4, primary_key=True) 35 session_key = models.TextField(unique=True, db_index=True) 36 user_id = models.UUIDField(null=True, blank=True, db_index=True) 37 38 session_data = models.JSONField(default=dict, blank=True) 39 40 class Meta: 41 verbose_name = _("Proxy Session") 42 verbose_name_plural = _("Proxy Sessions") 43 indexes = [ 44 models.Index(fields=["user_id"]), 45 ] 46 47 def __str__(self) -> str: 48 return f"Session {self.session_key[:8]}..."
Session storage for proxyv2 outposts using PostgreSQL
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.
Inherited Members
The requested object does not exist
The query returned multiple objects when only one was expected.
66class ProxyMode(models.TextChoices): 67 """All modes a Proxy provider can operate in""" 68 69 PROXY = "proxy" 70 FORWARD_SINGLE = "forward_single" 71 FORWARD_DOMAIN = "forward_domain"
All modes a Proxy provider can operate in
74class ProxyProvider(OutpostModel, OAuth2Provider): 75 """Protect applications that don't support any of the other 76 Protocols by using a Reverse-Proxy.""" 77 78 internal_host = models.TextField( 79 validators=[DomainlessURLValidator(schemes=("http", "https"))], 80 blank=True, 81 ) 82 external_host = models.TextField(validators=[DomainlessURLValidator(schemes=("http", "https"))]) 83 internal_host_ssl_validation = models.BooleanField( 84 default=True, 85 help_text=_("Validate SSL Certificates of upstream servers"), 86 verbose_name=_("Internal host SSL Validation"), 87 ) 88 mode = models.TextField( 89 default=ProxyMode.PROXY, 90 choices=ProxyMode.choices, 91 help_text=_( 92 "Enable support for forwardAuth in traefik and nginx auth_request. Exclusive with " 93 "internal_host." 94 ), 95 ) 96 97 skip_path_regex = models.TextField( 98 default="", 99 blank=True, 100 help_text=_( 101 "Regular expressions for which authentication is not required. " 102 "Each new line is interpreted as a new Regular Expression." 103 ), 104 ) 105 106 intercept_header_auth = models.BooleanField( 107 default=True, 108 help_text=_( 109 "When enabled, this provider will intercept the authorization header and authenticate " 110 "requests based on its value." 111 ), 112 ) 113 basic_auth_enabled = models.BooleanField( 114 default=False, 115 verbose_name=_("Set HTTP-Basic Authentication"), 116 help_text=_( 117 "Set a custom HTTP-Basic Authentication header based on values from authentik." 118 ), 119 ) 120 basic_auth_user_attribute = models.TextField( 121 blank=True, 122 verbose_name=_("HTTP-Basic Username Key"), 123 help_text=_( 124 "User/Group Attribute used for the user part of the HTTP-Basic Header. " 125 "If not set, the user's Email address is used." 126 ), 127 ) 128 basic_auth_password_attribute = models.TextField( 129 blank=True, 130 verbose_name=_("HTTP-Basic Password Key"), 131 help_text=_("User/Group Attribute used for the password part of the HTTP-Basic Header."), 132 ) 133 134 certificate = models.ForeignKey( 135 CertificateKeyPair, 136 on_delete=models.SET_NULL, 137 null=True, 138 blank=True, 139 ) 140 141 cookie_secret = models.TextField(default=get_cookie_secret) 142 cookie_domain = models.TextField(default="", blank=True) 143 144 @property 145 def component(self) -> str: 146 return "ak-provider-proxy-form" 147 148 @property 149 def icon_url(self) -> str | None: 150 return static("authentik/sources/proxy.svg") 151 152 @property 153 def serializer(self) -> type[Serializer]: 154 from authentik.providers.proxy.api import ProxyProviderSerializer 155 156 return ProxyProviderSerializer 157 158 @property 159 def launch_url(self) -> str | None: 160 """Use external_host as launch URL""" 161 return self.external_host 162 163 def set_oauth_defaults(self): 164 """Ensure all OAuth2-related settings are correct""" 165 self.client_type = ClientTypes.CONFIDENTIAL 166 self.signing_key = None 167 self.include_claims_in_id_token = True 168 scopes = ScopeMapping.objects.filter( 169 managed__in=[ 170 "goauthentik.io/providers/oauth2/scope-openid", 171 "goauthentik.io/providers/oauth2/scope-profile", 172 "goauthentik.io/providers/oauth2/scope-email", 173 "goauthentik.io/providers/oauth2/scope-entitlements", 174 "goauthentik.io/providers/proxy/scope-proxy", 175 ] 176 ) 177 self.property_mappings.add(*list(scopes)) 178 self.redirect_uris = _get_callback_url(self.external_host) 179 180 def __str__(self): 181 return f"Proxy Provider {self.name}" 182 183 def get_required_objects(self) -> Iterable[models.Model | str | tuple[str, models.Model]]: 184 required = [self] 185 if self.certificate is not None: 186 required.append(("authentik_crypto.view_certificatekeypair", self.certificate)) 187 required.append( 188 ("authentik_crypto.view_certificatekeypair_certificate", self.certificate) 189 ) 190 required.append(("authentik_crypto.view_certificatekeypair_key", self.certificate)) 191 return required 192 193 class Meta: 194 verbose_name = _("Proxy Provider") 195 verbose_name_plural = _("Proxy Providers") 196 authentik_used_by_shadows = ["authentik_providers_oauth2.oauth2provider"]
Protect applications that don't support any of the other Protocols by using a Reverse-Proxy.
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.
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.
152 @property 153 def serializer(self) -> type[Serializer]: 154 from authentik.providers.proxy.api import ProxyProviderSerializer 155 156 return ProxyProviderSerializer
Get serializer for this model
158 @property 159 def launch_url(self) -> str | None: 160 """Use external_host as launch URL""" 161 return self.external_host
Use external_host as launch URL
163 def set_oauth_defaults(self): 164 """Ensure all OAuth2-related settings are correct""" 165 self.client_type = ClientTypes.CONFIDENTIAL 166 self.signing_key = None 167 self.include_claims_in_id_token = True 168 scopes = ScopeMapping.objects.filter( 169 managed__in=[ 170 "goauthentik.io/providers/oauth2/scope-openid", 171 "goauthentik.io/providers/oauth2/scope-profile", 172 "goauthentik.io/providers/oauth2/scope-email", 173 "goauthentik.io/providers/oauth2/scope-entitlements", 174 "goauthentik.io/providers/proxy/scope-proxy", 175 ] 176 ) 177 self.property_mappings.add(*list(scopes)) 178 self.redirect_uris = _get_callback_url(self.external_host)
Ensure all OAuth2-related settings are correct
183 def get_required_objects(self) -> Iterable[models.Model | str | tuple[str, models.Model]]: 184 required = [self] 185 if self.certificate is not None: 186 required.append(("authentik_crypto.view_certificatekeypair", self.certificate)) 187 required.append( 188 ("authentik_crypto.view_certificatekeypair_certificate", self.certificate) 189 ) 190 required.append(("authentik_crypto.view_certificatekeypair_key", self.certificate)) 191 return required
Return a list of all required objects
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.providers.oauth2.models.OAuth2Provider
- client_type
- client_id
- client_secret
- logout_uri
- logout_method
- include_claims_in_id_token
- access_code_validity
- access_token_validity
- refresh_token_validity
- refresh_token_threshold
- sub_mode
- issuer_mode
- signing_key
- encryption_key
- jwt_federation_sources
- jwt_federation_providers
- jwt_key
- get_issuer
- redirect_uris
- encode
- encrypt
- webfinger
- get_client_type_display
- get_logout_method_display
- get_sub_mode_display
- get_issuer_mode_display
- signing_key_id
- encryption_key_id
- provider_ptr_id
- provider_ptr
- agentconnector_set
- oauth2provider_set
- accesstoken_set
- refreshtoken_set
- devicetoken_set
- proxyprovider
- ssfprovider_set
- authentik.core.models.Provider
- name
- authentication_flow
- invalidation_flow
- property_mappings
- backchannel_application
- is_backchannel
- objects
- authentication_flow_id
- invalidation_flow_id
- backchannel_application_id
- id
- application
- outpost_set
- oauth2provider
- ldapprovider
- racprovider
- radiusprovider
- samlprovider
- scimprovider
- googleworkspaceprovider
- microsoftentraprovider
- ssfprovider
The requested object does not exist
The query returned multiple objects when only one was expected.