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 ClientType, 20 GrantType, 21 OAuth2Provider, 22 RedirectURI, 23 RedirectURIMatchingMode, 24 ScopeMapping, 25) 26 27SCOPE_AK_PROXY = "ak_proxy" 28OUTPOST_CALLBACK_SIGNATURE = "X-authentik-auth-callback" 29 30 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]}..." 49 50 51def get_cookie_secret(): 52 """Generate random 32-character string for cookie-secret""" 53 return "".join(SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(32)) 54 55 56def _get_callback_url(uri: str) -> list[RedirectURI]: 57 return [ 58 RedirectURI( 59 RedirectURIMatchingMode.STRICT, 60 urljoin(uri, "outpost.goauthentik.io/callback") + f"?{OUTPOST_CALLBACK_SIGNATURE}=true", 61 ), 62 RedirectURI(RedirectURIMatchingMode.STRICT, uri + f"?{OUTPOST_CALLBACK_SIGNATURE}=true"), 63 ] 64 65 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" 72 73 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.grant_types = [ 166 GrantType.AUTHORIZATION_CODE, 167 GrantType.CLIENT_CREDENTIALS, 168 GrantType.PASSWORD, 169 ] 170 self.client_type = ClientType.CONFIDENTIAL 171 self.signing_key = None 172 self.include_claims_in_id_token = True 173 scopes = ScopeMapping.objects.filter( 174 managed__in=[ 175 "goauthentik.io/providers/oauth2/scope-openid", 176 "goauthentik.io/providers/oauth2/scope-profile", 177 "goauthentik.io/providers/oauth2/scope-email", 178 "goauthentik.io/providers/oauth2/scope-entitlements", 179 "goauthentik.io/providers/proxy/scope-proxy", 180 ] 181 ) 182 self.property_mappings.add(*list(scopes)) 183 self.redirect_uris = _get_callback_url(self.external_host) 184 185 def __str__(self): 186 return f"Proxy Provider {self.name}" 187 188 def get_required_objects(self) -> Iterable[models.Model | str | tuple[str, models.Model]]: 189 required = [self] 190 if self.certificate is not None: 191 required.append(("authentik_crypto.view_certificatekeypair", self.certificate)) 192 required.append( 193 ("authentik_crypto.view_certificatekeypair_certificate", self.certificate) 194 ) 195 required.append(("authentik_crypto.view_certificatekeypair_key", self.certificate)) 196 return required 197 198 class Meta: 199 verbose_name = _("Proxy Provider") 200 verbose_name_plural = _("Proxy Providers") 201 authentik_used_by_shadows = ["authentik_providers_oauth2.oauth2provider"]
32class ProxySession(InternallyManagedMixin, ExpiringModel): 33 """Session storage for proxyv2 outposts using PostgreSQL""" 34 35 uuid = models.UUIDField(default=uuid4, primary_key=True) 36 session_key = models.TextField(unique=True, db_index=True) 37 user_id = models.UUIDField(null=True, blank=True, db_index=True) 38 39 session_data = models.JSONField(default=dict, blank=True) 40 41 class Meta: 42 verbose_name = _("Proxy Session") 43 verbose_name_plural = _("Proxy Sessions") 44 indexes = [ 45 models.Index(fields=["user_id"]), 46 ] 47 48 def __str__(self) -> str: 49 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.
67class ProxyMode(models.TextChoices): 68 """All modes a Proxy provider can operate in""" 69 70 PROXY = "proxy" 71 FORWARD_SINGLE = "forward_single" 72 FORWARD_DOMAIN = "forward_domain"
All modes a Proxy provider can operate in
75class ProxyProvider(OutpostModel, OAuth2Provider): 76 """Protect applications that don't support any of the other 77 Protocols by using a Reverse-Proxy.""" 78 79 internal_host = models.TextField( 80 validators=[DomainlessURLValidator(schemes=("http", "https"))], 81 blank=True, 82 ) 83 external_host = models.TextField(validators=[DomainlessURLValidator(schemes=("http", "https"))]) 84 internal_host_ssl_validation = models.BooleanField( 85 default=True, 86 help_text=_("Validate SSL Certificates of upstream servers"), 87 verbose_name=_("Internal host SSL Validation"), 88 ) 89 mode = models.TextField( 90 default=ProxyMode.PROXY, 91 choices=ProxyMode.choices, 92 help_text=_( 93 "Enable support for forwardAuth in traefik and nginx auth_request. Exclusive with " 94 "internal_host." 95 ), 96 ) 97 98 skip_path_regex = models.TextField( 99 default="", 100 blank=True, 101 help_text=_( 102 "Regular expressions for which authentication is not required. " 103 "Each new line is interpreted as a new Regular Expression." 104 ), 105 ) 106 107 intercept_header_auth = models.BooleanField( 108 default=True, 109 help_text=_( 110 "When enabled, this provider will intercept the authorization header and authenticate " 111 "requests based on its value." 112 ), 113 ) 114 basic_auth_enabled = models.BooleanField( 115 default=False, 116 verbose_name=_("Set HTTP-Basic Authentication"), 117 help_text=_( 118 "Set a custom HTTP-Basic Authentication header based on values from authentik." 119 ), 120 ) 121 basic_auth_user_attribute = models.TextField( 122 blank=True, 123 verbose_name=_("HTTP-Basic Username Key"), 124 help_text=_( 125 "User/Group Attribute used for the user part of the HTTP-Basic Header. " 126 "If not set, the user's Email address is used." 127 ), 128 ) 129 basic_auth_password_attribute = models.TextField( 130 blank=True, 131 verbose_name=_("HTTP-Basic Password Key"), 132 help_text=_("User/Group Attribute used for the password part of the HTTP-Basic Header."), 133 ) 134 135 certificate = models.ForeignKey( 136 CertificateKeyPair, 137 on_delete=models.SET_NULL, 138 null=True, 139 blank=True, 140 ) 141 142 cookie_secret = models.TextField(default=get_cookie_secret) 143 cookie_domain = models.TextField(default="", blank=True) 144 145 @property 146 def component(self) -> str: 147 return "ak-provider-proxy-form" 148 149 @property 150 def icon_url(self) -> str | None: 151 return static("authentik/sources/proxy.svg") 152 153 @property 154 def serializer(self) -> type[Serializer]: 155 from authentik.providers.proxy.api import ProxyProviderSerializer 156 157 return ProxyProviderSerializer 158 159 @property 160 def launch_url(self) -> str | None: 161 """Use external_host as launch URL""" 162 return self.external_host 163 164 def set_oauth_defaults(self): 165 """Ensure all OAuth2-related settings are correct""" 166 self.grant_types = [ 167 GrantType.AUTHORIZATION_CODE, 168 GrantType.CLIENT_CREDENTIALS, 169 GrantType.PASSWORD, 170 ] 171 self.client_type = ClientType.CONFIDENTIAL 172 self.signing_key = None 173 self.include_claims_in_id_token = True 174 scopes = ScopeMapping.objects.filter( 175 managed__in=[ 176 "goauthentik.io/providers/oauth2/scope-openid", 177 "goauthentik.io/providers/oauth2/scope-profile", 178 "goauthentik.io/providers/oauth2/scope-email", 179 "goauthentik.io/providers/oauth2/scope-entitlements", 180 "goauthentik.io/providers/proxy/scope-proxy", 181 ] 182 ) 183 self.property_mappings.add(*list(scopes)) 184 self.redirect_uris = _get_callback_url(self.external_host) 185 186 def __str__(self): 187 return f"Proxy Provider {self.name}" 188 189 def get_required_objects(self) -> Iterable[models.Model | str | tuple[str, models.Model]]: 190 required = [self] 191 if self.certificate is not None: 192 required.append(("authentik_crypto.view_certificatekeypair", self.certificate)) 193 required.append( 194 ("authentik_crypto.view_certificatekeypair_certificate", self.certificate) 195 ) 196 required.append(("authentik_crypto.view_certificatekeypair_key", self.certificate)) 197 return required 198 199 class Meta: 200 verbose_name = _("Proxy Provider") 201 verbose_name_plural = _("Proxy Providers") 202 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.
153 @property 154 def serializer(self) -> type[Serializer]: 155 from authentik.providers.proxy.api import ProxyProviderSerializer 156 157 return ProxyProviderSerializer
Get serializer for this model
159 @property 160 def launch_url(self) -> str | None: 161 """Use external_host as launch URL""" 162 return self.external_host
Use external_host as launch URL
164 def set_oauth_defaults(self): 165 """Ensure all OAuth2-related settings are correct""" 166 self.grant_types = [ 167 GrantType.AUTHORIZATION_CODE, 168 GrantType.CLIENT_CREDENTIALS, 169 GrantType.PASSWORD, 170 ] 171 self.client_type = ClientType.CONFIDENTIAL 172 self.signing_key = None 173 self.include_claims_in_id_token = True 174 scopes = ScopeMapping.objects.filter( 175 managed__in=[ 176 "goauthentik.io/providers/oauth2/scope-openid", 177 "goauthentik.io/providers/oauth2/scope-profile", 178 "goauthentik.io/providers/oauth2/scope-email", 179 "goauthentik.io/providers/oauth2/scope-entitlements", 180 "goauthentik.io/providers/proxy/scope-proxy", 181 ] 182 ) 183 self.property_mappings.add(*list(scopes)) 184 self.redirect_uris = _get_callback_url(self.external_host)
Ensure all OAuth2-related settings are correct
189 def get_required_objects(self) -> Iterable[models.Model | str | tuple[str, models.Model]]: 190 required = [self] 191 if self.certificate is not None: 192 required.append(("authentik_crypto.view_certificatekeypair", self.certificate)) 193 required.append( 194 ("authentik_crypto.view_certificatekeypair_certificate", self.certificate) 195 ) 196 required.append(("authentik_crypto.view_certificatekeypair_key", self.certificate)) 197 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
- grant_types
- 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
- post_logout_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.