providers/radius: Add support for custom attributes (#10509)

* unrelated: show logs for failed blueprints

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add dictionaries

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* unrelated: remove some unused api functions

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add initial api

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* placeholder backend

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* idk

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add proper mappings

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L.
2024-07-25 19:08:33 +02:00
committed by GitHub
parent 650370d94c
commit 61c6887e82
24 changed files with 1450 additions and 165 deletions

View File

@ -23,9 +23,11 @@ class Command(BaseCommand):
for blueprint_path in options.get("blueprints", []):
content = BlueprintInstance(path=blueprint_path).retrieve()
importer = Importer.from_string(content)
valid, _ = importer.validate()
valid, logs = importer.validate()
if not valid:
self.stderr.write("blueprint invalid")
self.stderr.write("Blueprint invalid")
for log in logs:
self.stderr.write(f"\t{log.logger}: {log.event}: {log.attributes}")
sys_exit(1)
importer.apply()

View File

@ -20,6 +20,10 @@ class PropertyMappingManager:
_evaluators: list[PropertyMappingEvaluator]
globals: dict
__has_compiled: bool
def __init__(
self,
qs: QuerySet[PropertyMapping],
@ -33,7 +37,8 @@ class PropertyMappingManager:
self.query_set = qs
self.mapping_subclass = mapping_subclass
self.context_keys = context_keys
self.compile()
self.globals = {}
self.__has_compiled = False
def compile(self):
self._evaluators = []
@ -43,6 +48,7 @@ class PropertyMappingManager:
evaluator = PropertyMappingEvaluator(
mapping, **{key: None for key in self.context_keys}
)
evaluator._globals.update(self.globals)
# Compile and cache expression
evaluator.compile()
self._evaluators.append(evaluator)
@ -56,6 +62,9 @@ class PropertyMappingManager:
) -> Generator[tuple[dict, PropertyMapping], None]:
"""Iterate over all mappings that were pre-compiled and
execute all of them with the given context"""
if not self.__has_compiled:
self.compile()
self.__has_compiled = True
for mapping in self._evaluators:
mapping.set_context(user, request, **kwargs)
try:

View File

@ -5,7 +5,8 @@ from django.db.models.query import Q
from django_filters.filters import BooleanFilter
from django_filters.filterset import FilterSet
from rest_framework.fields import CharField, ListField, SerializerMethodField
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
@ -105,7 +106,7 @@ class LDAPOutpostConfigSerializer(ModelSerializer):
]
class LDAPOutpostConfigViewSet(ReadOnlyModelViewSet):
class LDAPOutpostConfigViewSet(ListModelMixin, GenericViewSet):
"""LDAPProvider Viewset"""
queryset = LDAPProvider.objects.filter(

View File

@ -6,7 +6,8 @@ from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema_field
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, ListField, ReadOnlyField, SerializerMethodField
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
@ -181,7 +182,7 @@ class ProxyOutpostConfigSerializer(ModelSerializer):
]
class ProxyOutpostConfigViewSet(ReadOnlyModelViewSet):
class ProxyOutpostConfigViewSet(ListModelMixin, GenericViewSet):
"""ProxyProvider Viewset"""
queryset = ProxyProvider.objects.filter(application__isnull=False)

View File

@ -1,71 +0,0 @@
"""RadiusProvider API Views"""
from rest_framework.fields import CharField, ListField
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer
from authentik.providers.radius.models import RadiusProvider
class RadiusProviderSerializer(ProviderSerializer):
"""RadiusProvider Serializer"""
outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all")
class Meta:
model = RadiusProvider
fields = ProviderSerializer.Meta.fields + [
"client_networks",
# Shared secret is not a write-only field, as
# an admin might have to view it
"shared_secret",
"outpost_set",
"mfa_support",
]
extra_kwargs = ProviderSerializer.Meta.extra_kwargs
class RadiusProviderViewSet(UsedByMixin, ModelViewSet):
"""RadiusProvider Viewset"""
queryset = RadiusProvider.objects.all()
serializer_class = RadiusProviderSerializer
ordering = ["name"]
search_fields = ["name", "client_networks"]
filterset_fields = {
"application": ["isnull"],
"name": ["iexact"],
"authorization_flow__slug": ["iexact"],
"client_networks": ["iexact"],
}
class RadiusOutpostConfigSerializer(ModelSerializer):
"""RadiusProvider Serializer"""
application_slug = CharField(source="application.slug")
auth_flow_slug = CharField(source="authorization_flow.slug")
class Meta:
model = RadiusProvider
fields = [
"pk",
"name",
"application_slug",
"auth_flow_slug",
"client_networks",
"shared_secret",
"mfa_support",
]
class RadiusOutpostConfigViewSet(ReadOnlyModelViewSet):
"""RadiusProvider Viewset"""
queryset = RadiusProvider.objects.filter(application__isnull=False)
serializer_class = RadiusOutpostConfigSerializer
ordering = ["name"]
search_fields = ["name"]
filterset_fields = ["name"]

View File

@ -0,0 +1,39 @@
"""Radius Property mappings API Views"""
from django_filters.filters import AllValuesMultipleFilter
from django_filters.filterset import FilterSet
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.property_mappings import PropertyMappingSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.providers.radius.models import RadiusProviderPropertyMapping
class RadiusProviderPropertyMappingSerializer(PropertyMappingSerializer):
"""RadiusProviderPropertyMapping Serializer"""
class Meta:
model = RadiusProviderPropertyMapping
fields = PropertyMappingSerializer.Meta.fields
class RadiusProviderPropertyMappingFilter(FilterSet):
"""Filter for RadiusProviderPropertyMapping"""
managed = extend_schema_field(OpenApiTypes.STR)(AllValuesMultipleFilter(field_name="managed"))
class Meta:
model = RadiusProviderPropertyMapping
fields = "__all__"
class RadiusProviderPropertyMappingViewSet(UsedByMixin, ModelViewSet):
"""RadiusProviderPropertyMapping Viewset"""
queryset = RadiusProviderPropertyMapping.objects.all()
serializer_class = RadiusProviderPropertyMappingSerializer
filterset_class = RadiusProviderPropertyMappingFilter
search_fields = ["name"]
ordering = ["name"]

View File

@ -0,0 +1,166 @@
"""RadiusProvider API Views"""
from base64 import b64encode
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from pyrad.dictionary import Attribute, Dictionary
from pyrad.packet import AuthPacket
from rest_framework.decorators import action
from rest_framework.fields import CharField, ListField
from rest_framework.mixins import ListModelMixin
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.core.expression.exceptions import PropertyMappingExpressionException
from authentik.core.models import Application
from authentik.events.models import Event, EventAction
from authentik.lib.expression.exceptions import ControlFlowException
from authentik.lib.sync.mapper import PropertyMappingManager
from authentik.lib.utils.errors import exception_to_string
from authentik.policies.api.exec import PolicyTestResultSerializer
from authentik.policies.engine import PolicyEngine
from authentik.policies.types import PolicyResult
from authentik.providers.radius.models import RadiusProvider, RadiusProviderPropertyMapping
class RadiusProviderSerializer(ProviderSerializer):
"""RadiusProvider Serializer"""
outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all")
class Meta:
model = RadiusProvider
fields = ProviderSerializer.Meta.fields + [
"client_networks",
# Shared secret is not a write-only field, as
# an admin might have to view it
"shared_secret",
"outpost_set",
"mfa_support",
]
extra_kwargs = ProviderSerializer.Meta.extra_kwargs
class RadiusProviderViewSet(UsedByMixin, ModelViewSet):
"""RadiusProvider Viewset"""
queryset = RadiusProvider.objects.all()
serializer_class = RadiusProviderSerializer
ordering = ["name"]
search_fields = ["name", "client_networks"]
filterset_fields = {
"application": ["isnull"],
"name": ["iexact"],
"authorization_flow__slug": ["iexact"],
"client_networks": ["iexact"],
}
class RadiusOutpostConfigSerializer(ModelSerializer):
"""RadiusProvider Serializer"""
application_slug = CharField(source="application.slug")
auth_flow_slug = CharField(source="authorization_flow.slug")
class Meta:
model = RadiusProvider
fields = [
"pk",
"name",
"application_slug",
"auth_flow_slug",
"client_networks",
"shared_secret",
"mfa_support",
]
class RadiusOutpostConfigViewSet(ListModelMixin, GenericViewSet):
"""RadiusProvider Viewset"""
queryset = RadiusProvider.objects.filter(application__isnull=False)
serializer_class = RadiusOutpostConfigSerializer
ordering = ["name"]
search_fields = ["name"]
filterset_fields = ["name"]
class RadiusCheckAccessSerializer(PassiveSerializer):
attributes = CharField(required=False)
access = PolicyTestResultSerializer()
def get_attributes(self, provider: RadiusProvider):
mapper = PropertyMappingManager(
provider.property_mappings.all().order_by("name").select_subclasses(),
RadiusProviderPropertyMapping,
["packet"],
)
dict = Dictionary("authentik/providers/radius/dictionaries/dictionary")
packet = AuthPacket()
packet.secret = provider.shared_secret
packet.dict = dict
def define_attribute(
vendor_code: int,
vendor_name: str,
attribute_name: str,
attribute_code: int,
attribute_type: str,
):
"""Dynamically add attribute to Radius packet"""
# Ensure the vendor exists
if vendor_code not in dict.vendors.backward or vendor_name not in dict.vendors.forward:
dict.vendors.Add(vendor_name, vendor_code)
if attribute_name not in dict.attributes:
dict.attributes[f"{vendor_name}-{attribute_name}"] = Attribute(
attribute_name, attribute_code, attribute_type, vendor=vendor_name
)
mapper.globals["define_attribute"] = define_attribute
try:
for _ in mapper.iter_eval(self.request.user, self.request, packet=packet):
pass
except (PropertyMappingExpressionException, ControlFlowException) as exc:
# Value error can be raised when assigning invalid data to an attribute
Event.new(
EventAction.CONFIGURATION_ERROR,
message=f"Failed to evaluate property-mapping {exception_to_string(exc)}",
mapping=exc.mapping,
).save()
return None
return b64encode(packet.RequestPacket()).decode()
@extend_schema(
request=None,
parameters=[OpenApiParameter("app_slug", OpenApiTypes.STR)],
responses={
200: RadiusCheckAccessSerializer(),
},
)
@action(detail=True)
def check_access(self, request: Request, pk) -> Response:
"""Check access to a single application by slug"""
provider = get_object_or_404(RadiusProvider, pk=pk)
application = get_object_or_404(Application, slug=request.query_params["app_slug"])
engine = PolicyEngine(application, request.user, request)
engine.use_cache = False
engine.build()
result = engine.result
access_response = PolicyResult(result.passing)
attributes = None
if result.passing:
attributes = self.get_attributes(provider)
response = self.RadiusCheckAccessSerializer(
instance={
"attributes": attributes,
"access": access_response,
}
)
return Response(response.data)

View File

@ -36,11 +36,13 @@
# directive to the end of the file if you want to see the old names
# in the logfiles too.
#
#$INCLUDE dictionary.compat # compability issues
#$INCLUDE dictionary.compat # compatibility issues
#$INCLUDE dictionary.acc
#$INCLUDE dictionary.ascend
#$INCLUDE dictionary.bay
#$INCLUDE dictionary.cisco
#$INCLUDE dictionary.aruba
$INCLUDE dictionary.cisco
$INCLUDE dictionary.microsoft
#$INCLUDE dictionary.livingston
#$INCLUDE dictionary.microsoft
#$INCLUDE dictionary.quintum

View File

@ -0,0 +1,132 @@
# -*- text -*-
# Copyright (C) 2023 The FreeRADIUS Server project and contributors
# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
# Version $Id$
#
# Version: $Id$
#
VENDOR Aruba 14823
BEGIN-VENDOR Aruba
ATTRIBUTE User-Role 1 string
ATTRIBUTE User-Vlan 2 integer
ATTRIBUTE Priv-Admin-User 3 integer
ATTRIBUTE Admin-Role 4 string
ATTRIBUTE Essid-Name 5 string
ATTRIBUTE Location-Id 6 string
ATTRIBUTE Port-Identifier 7 string
ATTRIBUTE MMS-User-Template 8 string
ATTRIBUTE Named-User-Vlan 9 string
ATTRIBUTE AP-Group 10 string
ATTRIBUTE Framed-IPv6-Address 11 string
ATTRIBUTE Device-Type 12 string
ATTRIBUTE No-DHCP-Fingerprint 14 integer
ATTRIBUTE Mdps-Device-Udid 15 string
ATTRIBUTE Mdps-Device-Imei 16 string
ATTRIBUTE Mdps-Device-Iccid 17 string
ATTRIBUTE Mdps-Max-Devices 18 integer
ATTRIBUTE Mdps-Device-Name 19 string
ATTRIBUTE Mdps-Device-Product 20 string
ATTRIBUTE Mdps-Device-Version 21 string
ATTRIBUTE Mdps-Device-Serial 22 string
ATTRIBUTE CPPM-Role 23 string
ATTRIBUTE AirGroup-User-Name 24 string
ATTRIBUTE AirGroup-Shared-User 25 string
ATTRIBUTE AirGroup-Shared-Role 26 string
ATTRIBUTE AirGroup-Device-Type 27 integer
ATTRIBUTE Auth-Survivability 28 string
ATTRIBUTE AS-User-Name 29 string
ATTRIBUTE AS-Credential-Hash 30 string
ATTRIBUTE WorkSpace-App-Name 31 string
ATTRIBUTE Mdps-Provisioning-Settings 32 string
ATTRIBUTE Mdps-Device-Profile 33 string
ATTRIBUTE AP-IP-Address 34 ipaddr
ATTRIBUTE AirGroup-Shared-Group 35 string
ATTRIBUTE User-Group 36 string
ATTRIBUTE Network-SSO-Token 37 string
ATTRIBUTE AirGroup-Version 38 integer
ATTRIBUTE Auth-SurvMethod 39 integer
ATTRIBUTE Port-Bounce-Host 40 integer
ATTRIBUTE Calea-Server-Ip 41 ipaddr
ATTRIBUTE Admin-Path 42 string
ATTRIBUTE Captive-Portal-URL 43 string
ATTRIBUTE MPSK-Passphrase 44 octets encrypt=2
ATTRIBUTE ACL-Server-Query-Info 45 string
ATTRIBUTE Command-String 46 string
ATTRIBUTE Network-Profile 47 string
ATTRIBUTE Admin-Device-Group 48 string
ATTRIBUTE PoE-Priority 49 integer
ATTRIBUTE Port-Auth-Mode 50 integer
ATTRIBUTE NAS-Filter-Rule 51 string
ATTRIBUTE QoS-Trust-Mode 52 integer
ATTRIBUTE UBT-Gateway-Role 53 string
ATTRIBUTE Gateway-Zone 54 string
ATTRIBUTE DPP-Bootstrapping-Key-SHA256 55 string
ATTRIBUTE DPP-Bootstrapping-Net-Access-Key-SHA256 56 string
ATTRIBUTE DPP-Bootstrapping-Key-B64 57 string
ATTRIBUTE STP-Admin-Edge-Port 58 integer
ATTRIBUTE UBT-Gateway-CPPM-Role 59 string
ATTRIBUTE AP-MAC-Address 60 string
ATTRIBUTE Device-MAC-Address 61 string
ATTRIBUTE MPSK-Key-Name 62 string
ATTRIBUTE Device-Traffic-Class 63 integer
ATTRIBUTE PVLAN-Port-Type 64 integer
ATTRIBUTE Network-Test 65 integer
ATTRIBUTE MPSK-Lookup-Info 66 string encrypt=1
ATTRIBUTE AVPair 67 string
ATTRIBUTE DPP-Service-Type 68 integer
ATTRIBUTE User-Mgmt-Interface 69 string
ATTRIBUTE Poe-Allocate-By-Method 70 integer
ATTRIBUTE DPP-AKMs 71 string
ATTRIBUTE DPP-Passphrase 72 string encrypt=2
VALUE AirGroup-Device-Type Personal-Device 1
VALUE AirGroup-Device-Type Shared-Device 2
VALUE AirGroup-Device-Type Deleted-Device 3
VALUE AirGroup-Version AirGroup-v1 1
VALUE AirGroup-Version AirGroup-v2 2
VALUE PoE-Priority Critical 0
VALUE PoE-Priority High 1
VALUE PoE-Priority Low 2
VALUE Port-Auth-Mode Infrastructure-Mode 1
VALUE Port-Auth-Mode Client-Mode 2
VALUE Port-Auth-Mode Multi-Domain-Mode 3
VALUE QoS-Trust-Mode DSCP 0
VALUE QoS-Trust-Mode QoS 1
VALUE QoS-Trust-Mode None 2
VALUE STP-Admin-Edge-Port Disable 0
VALUE STP-Admin-Edge-Port Enable 1
VALUE PVLAN-Port-Type None 0
VALUE PVLAN-Port-Type Promiscuous 1
VALUE PVLAN-Port-Type Secondary 2
VALUE DPP-Service-Type DDP-Boostrap-Authorization 1
VALUE DPP-Service-Type DDP-Identity-Update 2
VALUE DPP-Service-Type DDP-Net-Access 3
VALUE PoE-Allocate-By-Method Class 1
VALUE PoE-Allocate-By-Method Usage 2
END-VENDOR Aruba
ALIAS Aruba Vendor-Specific.Aruba

View File

@ -0,0 +1,231 @@
# -*- text -*-
# Copyright (C) 2023 The FreeRADIUS Server project and contributors
# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
# Version $Id$
#
# dictionary.cisco
#
# Accounting VSAs originally by
# "Marcelo M. Sosa Lugones" <marcelo@sosa.com.ar>
#
# Version: $Id$
#
# For documentation on Cisco RADIUS attributes, see:
#
# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_serv/vapp_dev/vsaig3.htm
#
# For general documentation on Cisco RADIUS configuration, see:
#
# http://www.cisco.com/en/US/partner/tech/tk583/tk547/tsd_technology_support_sub-protocol_home.html
#
VENDOR Cisco 9
#
# Standard attribute
#
BEGIN-VENDOR Cisco
ATTRIBUTE AVPair 1 string
ATTRIBUTE NAS-Port 2 string
#
# T.37 Store-and-Forward attributes.
#
ATTRIBUTE Fax-Account-Id-Origin 3 string
ATTRIBUTE Fax-Msg-Id 4 string
ATTRIBUTE Fax-Pages 5 string
ATTRIBUTE Fax-Coverpage-Flag 6 string
ATTRIBUTE Fax-Modem-Time 7 string
ATTRIBUTE Fax-Connect-Speed 8 string
ATTRIBUTE Fax-Recipient-Count 9 string
ATTRIBUTE Fax-Process-Abort-Flag 10 string
ATTRIBUTE Fax-Dsn-Address 11 string
ATTRIBUTE Fax-Dsn-Flag 12 string
ATTRIBUTE Fax-Mdn-Address 13 string
ATTRIBUTE Fax-Mdn-Flag 14 string
ATTRIBUTE Fax-Auth-Status 15 string
ATTRIBUTE Email-Server-Address 16 string
ATTRIBUTE Email-Server-Ack-Flag 17 string
ATTRIBUTE Gateway-Id 18 string
ATTRIBUTE Call-Type 19 string
ATTRIBUTE Port-Used 20 string
ATTRIBUTE Abort-Cause 21 string
#
# Voice over IP attributes.
#
ATTRIBUTE h323-remote-address 23 string
ATTRIBUTE h323-conf-id 24 string
ATTRIBUTE h323-setup-time 25 string
ATTRIBUTE h323-call-origin 26 string
ATTRIBUTE h323-call-type 27 string
ATTRIBUTE h323-connect-time 28 string
ATTRIBUTE h323-disconnect-time 29 string
ATTRIBUTE h323-disconnect-cause 30 string
ATTRIBUTE h323-voice-quality 31 string
ATTRIBUTE h323-gw-id 33 string
ATTRIBUTE h323-incoming-conf-id 35 string
ATTRIBUTE Policy-Up 37 string
ATTRIBUTE Policy-Down 38 string
ATTRIBUTE Relay-Information-Option 46 string
ATTRIBUTE DHCP-User-Class 47 string
ATTRIBUTE DHCP-Vendor-Class 48 string
ATTRIBUTE DHCP-Relay-GiAddr 50 string
ATTRIBUTE Service-Name 51 string
ATTRIBUTE Parent-Session-Id 52 string
ATTRIBUTE Sub-QoS-Pol-In 55 string
ATTRIBUTE Sub-QoS-Pol-Out 56 string
ATTRIBUTE In-ACL 57 string
ATTRIBUTE Out-ACL 58 string
ATTRIBUTE Sub-PBR-Policy-In 59 string
ATTRIBUTE Sub-Activate-Service 60 string
ATTRIBUTE IPv6-In-ACL 61 string
ATTRIBUTE IPv6-Out-ACL 62 string
ATTRIBUTE Sub-Deactivate-Service 63 string
ATTRIBUTE DHCP-Subscriber-Id 65 string
ATTRIBUTE DHCPv6-Link-Address 66 string
ATTRIBUTE sip-conf-id 100 string
ATTRIBUTE h323-credit-amount 101 string
ATTRIBUTE h323-credit-time 102 string
ATTRIBUTE h323-return-code 103 string
ATTRIBUTE h323-prompt-id 104 string
ATTRIBUTE h323-time-and-day 105 string
ATTRIBUTE h323-redirect-number 106 string
ATTRIBUTE h323-preferred-lang 107 string
ATTRIBUTE h323-redirect-ip-address 108 string
ATTRIBUTE h323-billing-model 109 string
ATTRIBUTE h323-currency 110 string
ATTRIBUTE subscriber 111 string
ATTRIBUTE gw-rxd-cdn 112 string
ATTRIBUTE gw-final-xlated-cdn 113 string
ATTRIBUTE remote-media-address 114 string
ATTRIBUTE release-source 115 string
ATTRIBUTE gw-rxd-cgn 116 string
ATTRIBUTE gw-final-xlated-cgn 117 string
# SIP Attributes
ATTRIBUTE call-id 141 string
ATTRIBUTE session-protocol 142 string
ATTRIBUTE method 143 string
ATTRIBUTE prev-hop-via 144 string
ATTRIBUTE prev-hop-ip 145 string
ATTRIBUTE incoming-req-uri 146 string
ATTRIBUTE outgoing-req-uri 147 string
ATTRIBUTE next-hop-ip 148 string
ATTRIBUTE next-hop-dn 149 string
ATTRIBUTE sip-hdr 150 string
ATTRIBUTE dsp-id 151 string
#
# Extra attributes sent by the Cisco, if you configure
# "radius-server vsa accounting" (requires IOS11.2+).
#
ATTRIBUTE Multilink-ID 187 integer
ATTRIBUTE Num-In-Multilink 188 integer
ATTRIBUTE Pre-Input-Octets 190 integer
ATTRIBUTE Pre-Output-Octets 191 integer
ATTRIBUTE Pre-Input-Packets 192 integer
ATTRIBUTE Pre-Output-Packets 193 integer
ATTRIBUTE Maximum-Time 194 integer
ATTRIBUTE Disconnect-Cause 195 integer
ATTRIBUTE Data-Rate 197 integer
ATTRIBUTE PreSession-Time 198 integer
ATTRIBUTE PW-Lifetime 208 integer
ATTRIBUTE IP-Direct 209 integer
ATTRIBUTE PPP-VJ-Slot-Comp 210 integer
ATTRIBUTE PPP-Async-Map 212 integer
ATTRIBUTE IP-Pool-Definition 217 string
ATTRIBUTE Assign-IP-Pool 218 integer
ATTRIBUTE Route-IP 228 integer
ATTRIBUTE Link-Compression 233 integer
ATTRIBUTE Target-Util 234 integer
ATTRIBUTE Maximum-Channels 235 integer
ATTRIBUTE Data-Filter 242 integer
ATTRIBUTE Call-Filter 243 integer
ATTRIBUTE Idle-Limit 244 integer
ATTRIBUTE Subscriber-Password 249 string
ATTRIBUTE Account-Info 250 string
ATTRIBUTE Service-Info 251 string
ATTRIBUTE Command-Code 252 string
ATTRIBUTE Control-Info 253 string
ATTRIBUTE Xmit-Rate 255 integer
VALUE Disconnect-Cause No-Reason 0
VALUE Disconnect-Cause No-Disconnect 1
VALUE Disconnect-Cause Unknown 2
VALUE Disconnect-Cause Call-Disconnect 3
VALUE Disconnect-Cause CLID-Authentication-Failure 4
VALUE Disconnect-Cause No-Modem-Available 9
VALUE Disconnect-Cause No-Carrier 10
VALUE Disconnect-Cause Lost-Carrier 11
VALUE Disconnect-Cause No-Detected-Result-Codes 12
VALUE Disconnect-Cause User-Ends-Session 20
VALUE Disconnect-Cause Idle-Timeout 21
VALUE Disconnect-Cause Exit-Telnet-Session 22
VALUE Disconnect-Cause No-Remote-IP-Addr 23
VALUE Disconnect-Cause Exit-Raw-TCP 24
VALUE Disconnect-Cause Password-Fail 25
VALUE Disconnect-Cause Raw-TCP-Disabled 26
VALUE Disconnect-Cause Control-C-Detected 27
VALUE Disconnect-Cause EXEC-Program-Destroyed 28
VALUE Disconnect-Cause Close-Virtual-Connection 29
VALUE Disconnect-Cause End-Virtual-Connection 30
VALUE Disconnect-Cause Exit-Rlogin 31
VALUE Disconnect-Cause Invalid-Rlogin-Option 32
VALUE Disconnect-Cause Insufficient-Resources 33
VALUE Disconnect-Cause Timeout-PPP-LCP 40
VALUE Disconnect-Cause Failed-PPP-LCP-Negotiation 41
VALUE Disconnect-Cause Failed-PPP-PAP-Auth-Fail 42
VALUE Disconnect-Cause Failed-PPP-CHAP-Auth 43
VALUE Disconnect-Cause Failed-PPP-Remote-Auth 44
VALUE Disconnect-Cause PPP-Remote-Terminate 45
VALUE Disconnect-Cause PPP-Closed-Event 46
VALUE Disconnect-Cause NCP-Closed-PPP 47
VALUE Disconnect-Cause MP-Error-PPP 48
VALUE Disconnect-Cause PPP-Maximum-Channels 49
VALUE Disconnect-Cause Tables-Full 50
VALUE Disconnect-Cause Resources-Full 51
VALUE Disconnect-Cause Invalid-IP-Address 52
VALUE Disconnect-Cause Bad-Hostname 53
VALUE Disconnect-Cause Bad-Port 54
VALUE Disconnect-Cause Reset-TCP 60
VALUE Disconnect-Cause TCP-Connection-Refused 61
VALUE Disconnect-Cause Timeout-TCP 62
VALUE Disconnect-Cause Foreign-Host-Close-TCP 63
VALUE Disconnect-Cause TCP-Network-Unreachable 64
VALUE Disconnect-Cause TCP-Host-Unreachable 65
VALUE Disconnect-Cause TCP-Network-Admin-Unreachable 66
VALUE Disconnect-Cause TCP-Port-Unreachable 67
VALUE Disconnect-Cause Session-Timeout 100
VALUE Disconnect-Cause Session-Failed-Security 101
VALUE Disconnect-Cause Session-End-Callback 102
VALUE Disconnect-Cause Invalid-Protocol 120
VALUE Disconnect-Cause RADIUS-Disconnect 150
VALUE Disconnect-Cause Local-Admin-Disconnect 151
VALUE Disconnect-Cause SNMP-Disconnect 152
VALUE Disconnect-Cause V110-Retries 160
VALUE Disconnect-Cause PPP-Authentication-Timeout 170
VALUE Disconnect-Cause Local-Hangup 180
VALUE Disconnect-Cause Remote-Hangup 185
VALUE Disconnect-Cause T1-Quiesced 190
VALUE Disconnect-Cause Call-Duration 195
VALUE Disconnect-Cause VPN-User-Disconnect 600
VALUE Disconnect-Cause VPN-Carrier-Loss 601
VALUE Disconnect-Cause VPN-No-Resources 602
VALUE Disconnect-Cause VPN-Bad-Control-Packet 603
VALUE Disconnect-Cause VPN-Admin-Disconnect 604
VALUE Disconnect-Cause VPN-Tunnel-Shut 605
VALUE Disconnect-Cause VPN-Local-Disconnect 606
VALUE Disconnect-Cause VPN-Session-Limit 607
VALUE Disconnect-Cause VPN-Call-Redirect 608
END-VENDOR Cisco
ALIAS Cisco Vendor-Specific.Cisco

View File

@ -0,0 +1,174 @@
# -*- text -*-
# Copyright (C) 2023 The FreeRADIUS Server project and contributors
# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
# Version $Id$
#
# Microsoft's VSA's, from RFC 2548
#
# $Id$
#
VENDOR Microsoft 311
BEGIN-VENDOR Microsoft
ATTRIBUTE CHAP-Response 1 octets[50]
ATTRIBUTE CHAP-Error 2 string
ATTRIBUTE CHAP-CPW-1 3 octets[70]
ATTRIBUTE CHAP-CPW-2 4 octets[84]
ATTRIBUTE CHAP-LM-Enc-PW 5 octets
ATTRIBUTE CHAP-NT-Enc-PW 6 octets
ATTRIBUTE MPPE-Encryption-Policy 7 integer
VALUE MPPE-Encryption-Policy Encryption-Allowed 1
VALUE MPPE-Encryption-Policy Encryption-Required 2
# This is referred to as both singular and plural in the RFC.
# Plural seems to make more sense.
ATTRIBUTE MPPE-Encryption-Type 8 integer
ATTRIBUTE MPPE-Encryption-Types 8 integer
VALUE MPPE-Encryption-Types RC4-40bit-Allowed 1
VALUE MPPE-Encryption-Types RC4-128bit-Allowed 2
VALUE MPPE-Encryption-Types RC4-40or128-bit-Allowed 6
ATTRIBUTE RAS-Vendor 9 integer # content is Vendor-ID
ATTRIBUTE CHAP-Domain 10 string
ATTRIBUTE CHAP-Challenge 11 octets
ATTRIBUTE CHAP-MPPE-Keys 12 octets[24] encrypt=1
ATTRIBUTE BAP-Usage 13 integer
ATTRIBUTE Link-Utilization-Threshold 14 integer # values are 1-100
ATTRIBUTE Link-Drop-Time-Limit 15 integer
ATTRIBUTE MPPE-Send-Key 16 octets encrypt=2
ATTRIBUTE MPPE-Recv-Key 17 octets encrypt=2
ATTRIBUTE RAS-Version 18 string
ATTRIBUTE Old-ARAP-Password 19 octets
ATTRIBUTE New-ARAP-Password 20 octets
ATTRIBUTE ARAP-PW-Change-Reason 21 integer
ATTRIBUTE Filter 22 octets
ATTRIBUTE Acct-Auth-Type 23 integer
ATTRIBUTE Acct-EAP-Type 24 integer
ATTRIBUTE CHAP2-Response 25 octets[50]
ATTRIBUTE CHAP2-Success 26 octets
ATTRIBUTE CHAP2-CPW 27 octets[68]
ATTRIBUTE Primary-DNS-Server 28 ipaddr
ATTRIBUTE Secondary-DNS-Server 29 ipaddr
ATTRIBUTE Primary-NBNS-Server 30 ipaddr
ATTRIBUTE Secondary-NBNS-Server 31 ipaddr
#ATTRIBUTE ARAP-Challenge 33 octets[8]
## RNAP
#
# http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BRNAP%5D.pdf
ATTRIBUTE RAS-Client-Name 34 string
ATTRIBUTE RAS-Client-Version 35 string
ATTRIBUTE Quarantine-IPFilter 36 octets
ATTRIBUTE Quarantine-Session-Timeout 37 integer
ATTRIBUTE User-Security-Identity 40 string
ATTRIBUTE Identity-Type 41 integer
ATTRIBUTE Service-Class 42 string
ATTRIBUTE Quarantine-User-Class 44 string
ATTRIBUTE Quarantine-State 45 integer
ATTRIBUTE Quarantine-Grace-Time 46 integer
ATTRIBUTE Network-Access-Server-Type 47 integer
ATTRIBUTE AFW-Zone 48 integer
VALUE AFW-Zone AFW-Zone-Boundary-Policy 1
VALUE AFW-Zone AFW-Zone-Unprotected-Policy 2
VALUE AFW-Zone AFW-Zone-Protected-Policy 3
ATTRIBUTE AFW-Protection-Level 49 integer
VALUE AFW-Protection-Level HECP-Response-Sign-Only 1
VALUE AFW-Protection-Level HECP-Response-Sign-And-Encrypt 2
ATTRIBUTE Machine-Name 50 string
ATTRIBUTE IPv6-Filter 51 octets
ATTRIBUTE IPv4-Remediation-Servers 52 octets
ATTRIBUTE IPv6-Remediation-Servers 53 octets
ATTRIBUTE RNAP-Not-Quarantine-Capable 54 integer
VALUE RNAP-Not-Quarantine-Capable SoH-Sent 0
VALUE RNAP-Not-Quarantine-Capable SoH-Not-Sent 1
ATTRIBUTE Quarantine-SOH 55 octets
ATTRIBUTE RAS-Correlation 56 octets
# Or this might be 56?
ATTRIBUTE Extended-Quarantine-State 57 integer
ATTRIBUTE HCAP-User-Groups 58 string
ATTRIBUTE HCAP-Location-Group-Name 59 string
ATTRIBUTE HCAP-User-Name 60 string
ATTRIBUTE User-IPv4-Address 61 ipaddr
ATTRIBUTE User-IPv6-Address 62 ipv6addr
ATTRIBUTE TSG-Device-Redirection 63 integer
#
# Integer Translations
#
# BAP-Usage Values
VALUE BAP-Usage Not-Allowed 0
VALUE BAP-Usage Allowed 1
VALUE BAP-Usage Required 2
# ARAP-Password-Change-Reason Values
VALUE ARAP-PW-Change-Reason Just-Change-Password 1
VALUE ARAP-PW-Change-Reason Expired-Password 2
VALUE ARAP-PW-Change-Reason Admin-Requires-Password-Change 3
VALUE ARAP-PW-Change-Reason Password-Too-Short 4
# Acct-Auth-Type Values
VALUE Acct-Auth-Type PAP 1
VALUE Acct-Auth-Type CHAP 2
VALUE Acct-Auth-Type CHAP-1 3
VALUE Acct-Auth-Type CHAP-2 4
VALUE Acct-Auth-Type EAP 5
# Acct-EAP-Type Values
VALUE Acct-EAP-Type MD5 4
VALUE Acct-EAP-Type OTP 5
VALUE Acct-EAP-Type Generic-Token-Card 6
VALUE Acct-EAP-Type TLS 13
# Identity-Type Values
VALUE Identity-Type Machine-Health-Check 1
VALUE Identity-Type Ignore-User-Lookup-Failure 2
# Quarantine-State Values
VALUE Quarantine-State Full-Access 0
VALUE Quarantine-State Quarantine 1
VALUE Quarantine-State Probation 2
# Network-Access-Server-Type Values
VALUE Network-Access-Server-Type Unspecified 0
VALUE Network-Access-Server-Type Terminal-Server-Gateway 1
VALUE Network-Access-Server-Type Remote-Access-Server 2
VALUE Network-Access-Server-Type DHCP-Server 3
VALUE Network-Access-Server-Type Wireless-Access-Point 4
VALUE Network-Access-Server-Type HRA 5
VALUE Network-Access-Server-Type HCAP-Server 6
# Extended-Quarantine-State Values
VALUE Extended-Quarantine-State Transition 1
VALUE Extended-Quarantine-State Infected 2
VALUE Extended-Quarantine-State Unknown 3
VALUE Extended-Quarantine-State No-Data 4
END-VENDOR Microsoft
ALIAS Microsoft Vendor-Specific.Microsoft

View File

@ -0,0 +1,36 @@
# Generated by Django 5.0.7 on 2024-07-17 10:01
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0035_alter_group_options_and_more"),
("authentik_providers_radius", "0002_radiusprovider_mfa_support"),
]
operations = [
migrations.CreateModel(
name="RadiusProviderPropertyMapping",
fields=[
(
"propertymapping_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_core.propertymapping",
),
),
],
options={
"verbose_name": "Radius Property Mapping",
"verbose_name_plural": "Radius Property Mappings",
},
bases=("authentik_core.propertymapping",),
),
]

View File

@ -5,7 +5,7 @@ from django.templatetags.static import static
from django.utils.translation import gettext_lazy as _
from rest_framework.serializers import Serializer
from authentik.core.models import Provider
from authentik.core.models import PropertyMapping, Provider
from authentik.lib.generators import generate_id
from authentik.outposts.models import OutpostModel
@ -53,7 +53,7 @@ class RadiusProvider(OutpostModel, Provider):
@property
def serializer(self) -> type[Serializer]:
from authentik.providers.radius.api import RadiusProviderSerializer
from authentik.providers.radius.api.providers import RadiusProviderSerializer
return RadiusProviderSerializer
@ -63,3 +63,25 @@ class RadiusProvider(OutpostModel, Provider):
class Meta:
verbose_name = _("Radius Provider")
verbose_name_plural = _("Radius Providers")
class RadiusProviderPropertyMapping(PropertyMapping):
@property
def component(self) -> str:
return "ak-property-mapping-radius-form"
@property
def serializer(self) -> type[Serializer]:
from authentik.providers.radius.api.property_mappings import (
RadiusProviderPropertyMappingSerializer,
)
return RadiusProviderPropertyMappingSerializer
def __str__(self):
return f"Radius Property Mapping {self.name}"
class Meta:
verbose_name = _("Radius Property Mapping")
verbose_name_plural = _("Radius Property Mappings")

View File

@ -1,8 +1,13 @@
"""API URLs"""
from authentik.providers.radius.api import RadiusOutpostConfigViewSet, RadiusProviderViewSet
from authentik.providers.radius.api.property_mappings import RadiusProviderPropertyMappingViewSet
from authentik.providers.radius.api.providers import (
RadiusOutpostConfigViewSet,
RadiusProviderViewSet,
)
api_urlpatterns = [
("propertymappings/radius", RadiusProviderPropertyMappingViewSet),
("outposts/radius", RadiusOutpostConfigViewSet, "radiusprovideroutpost"),
("providers/radius", RadiusProviderViewSet),
]

View File

@ -744,6 +744,43 @@
}
}
},
{
"type": "object",
"required": [
"model",
"identifiers"
],
"properties": {
"model": {
"const": "authentik_providers_radius.radiusproviderpropertymapping"
},
"id": {
"type": "string"
},
"state": {
"type": "string",
"enum": [
"absent",
"present",
"created",
"must_created"
],
"default": "present"
},
"conditions": {
"type": "array",
"items": {
"type": "boolean"
}
},
"attrs": {
"$ref": "#/$defs/model_authentik_providers_radius.radiusproviderpropertymapping"
},
"identifiers": {
"$ref": "#/$defs/model_authentik_providers_radius.radiusproviderpropertymapping"
}
}
},
{
"type": "object",
"required": [
@ -3520,6 +3557,7 @@
"authentik_providers_oauth2.oauth2provider",
"authentik_providers_proxy.proxyprovider",
"authentik_providers_radius.radiusprovider",
"authentik_providers_radius.radiusproviderpropertymapping",
"authentik_providers_saml.samlprovider",
"authentik_providers_saml.samlpropertymapping",
"authentik_providers_scim.scimprovider",
@ -4199,6 +4237,31 @@
},
"required": []
},
"model_authentik_providers_radius.radiusproviderpropertymapping": {
"type": "object",
"properties": {
"managed": {
"type": [
"string",
"null"
],
"minLength": 1,
"title": "Managed by authentik",
"description": "Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update."
},
"name": {
"type": "string",
"minLength": 1,
"title": "Name"
},
"expression": {
"type": "string",
"minLength": 1,
"title": "Expression"
}
},
"required": []
},
"model_authentik_providers_saml.samlprovider": {
"type": "object",
"properties": {

View File

@ -46,6 +46,7 @@ func (rs *RadiusServer) Refresh() error {
MFASupport: provider.GetMfaSupport(),
appSlug: provider.ApplicationSlug,
flowSlug: provider.AuthFlowSlug,
providerId: provider.Pk,
s: rs,
log: logger,
}

View File

@ -1,6 +1,8 @@
package radius
import (
"encoding/base64"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"goauthentik.io/internal/outpost/flow"
@ -43,7 +45,7 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR
_ = w.Write(r.Response(radius.CodeAccessReject))
return
}
access, err := fe.CheckApplicationAccess(r.pi.appSlug)
access, _, err := fe.ApiClient().OutpostsApi.OutpostsRadiusCheckAccessRetrieve(r.Context(), r.pi.providerId).AppSlug(r.pi.appSlug).Execute()
if err != nil {
r.Log().WithField("username", username).WithError(err).Warning("failed to check access")
_ = w.Write(r.Response(radius.CodeAccessReject))
@ -54,7 +56,7 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR
}).Inc()
return
}
if !access {
if !access.Access.Passing {
r.Log().WithField("username", username).Info("Access denied for user")
_ = w.Write(r.Response(radius.CodeAccessReject))
metrics.RequestsRejected.With(prometheus.Labels{
@ -64,5 +66,22 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR
}).Inc()
return
}
_ = w.Write(r.Response(radius.CodeAccessAccept))
res := r.Response(radius.CodeAccessAccept)
defer func() { _ = w.Write(res) }()
if !access.HasAttributes() {
r.Log().Debug("No attributes")
return
}
rawData, err := base64.StdEncoding.DecodeString(access.GetAttributes())
if err != nil {
r.Log().WithError(err).Warning("failed to decode attributes from core")
return
}
p, err := radius.Parse(rawData, r.pi.SharedSecret)
if err != nil {
r.Log().WithError(err).Warning("failed to parse attributes from core")
}
for _, attr := range p.Attributes {
res.Add(attr.Type, attr.Attribute)
}
}

View File

@ -21,6 +21,7 @@ type ProviderInstance struct {
appSlug string
flowSlug string
providerId int32
s *RadiusServer
log *log.Entry
}

View File

@ -9637,40 +9637,6 @@ paths:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/outposts/ldap/{id}/:
get:
operationId: outposts_ldap_retrieve
description: LDAPProvider Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this LDAP Provider.
required: true
tags:
- outposts
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/LDAPOutpostConfig'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/outposts/proxy/:
get:
operationId: outposts_proxy_list
@ -9727,40 +9693,6 @@ paths:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/outposts/proxy/{id}/:
get:
operationId: outposts_proxy_retrieve
description: ProxyProvider Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Proxy Provider.
required: true
tags:
- outposts
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ProxyOutpostConfig'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/outposts/radius/:
get:
operationId: outposts_radius_list
@ -9817,11 +9749,15 @@ paths:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/outposts/radius/{id}/:
/outposts/radius/{id}/check_access/:
get:
operationId: outposts_radius_retrieve
description: RadiusProvider Viewset
operationId: outposts_radius_check_access_retrieve
description: Check access to a single application by slug
parameters:
- in: query
name: app_slug
schema:
type: string
- in: path
name: id
schema:
@ -9837,7 +9773,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusOutpostConfig'
$ref: '#/components/schemas/RadiusCheckAccess'
description: ''
'400':
content:
@ -14591,6 +14527,292 @@ paths:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/propertymappings/radius/:
get:
operationId: propertymappings_radius_list
description: RadiusProviderPropertyMapping Viewset
parameters:
- in: query
name: expression
schema:
type: string
- in: query
name: managed
schema:
type: array
items:
type: string
explode: true
style: form
- in: query
name: name
schema:
type: string
- name: ordering
required: false
in: query
description: Which field to use when ordering the results.
schema:
type: string
- name: page
required: false
in: query
description: A page number within the paginated result set.
schema:
type: integer
- name: page_size
required: false
in: query
description: Number of results to return per page.
schema:
type: integer
- in: query
name: pm_uuid
schema:
type: string
format: uuid
- name: search
required: false
in: query
description: A search term.
schema:
type: string
tags:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedRadiusProviderPropertyMappingList'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
post:
operationId: propertymappings_radius_create
description: RadiusProviderPropertyMapping Viewset
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusProviderPropertyMappingRequest'
required: true
security:
- authentik: []
responses:
'201':
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusProviderPropertyMapping'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/propertymappings/radius/{pm_uuid}/:
get:
operationId: propertymappings_radius_retrieve
description: RadiusProviderPropertyMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Radius Property Mapping.
required: true
tags:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusProviderPropertyMapping'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
put:
operationId: propertymappings_radius_update
description: RadiusProviderPropertyMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Radius Property Mapping.
required: true
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusProviderPropertyMappingRequest'
required: true
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusProviderPropertyMapping'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
patch:
operationId: propertymappings_radius_partial_update
description: RadiusProviderPropertyMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Radius Property Mapping.
required: true
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedRadiusProviderPropertyMappingRequest'
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/RadiusProviderPropertyMapping'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
delete:
operationId: propertymappings_radius_destroy
description: RadiusProviderPropertyMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Radius Property Mapping.
required: true
tags:
- propertymappings
security:
- authentik: []
responses:
'204':
description: No response body
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/propertymappings/radius/{pm_uuid}/used_by/:
get:
operationId: propertymappings_radius_used_by_list
description: Get a list of all objects that use this object
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Radius Property Mapping.
required: true
tags:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UsedBy'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/propertymappings/saml/:
get:
operationId: propertymappings_saml_list
@ -20798,6 +21020,7 @@ paths:
- authentik_providers_rac.racpropertymapping
- authentik_providers_rac.racprovider
- authentik_providers_radius.radiusprovider
- authentik_providers_radius.radiusproviderpropertymapping
- authentik_providers_saml.samlpropertymapping
- authentik_providers_saml.samlprovider
- authentik_providers_scim.scimmapping
@ -21017,6 +21240,7 @@ paths:
- authentik_providers_rac.racpropertymapping
- authentik_providers_rac.racprovider
- authentik_providers_radius.radiusprovider
- authentik_providers_radius.radiusproviderpropertymapping
- authentik_providers_saml.samlpropertymapping
- authentik_providers_saml.samlprovider
- authentik_providers_scim.scimmapping
@ -38602,6 +38826,7 @@ components:
- authentik_providers_oauth2.oauth2provider
- authentik_providers_proxy.proxyprovider
- authentik_providers_radius.radiusprovider
- authentik_providers_radius.radiusproviderpropertymapping
- authentik_providers_saml.samlprovider
- authentik_providers_saml.samlpropertymapping
- authentik_providers_scim.scimprovider
@ -40493,6 +40718,18 @@ components:
required:
- pagination
- results
PaginatedRadiusProviderPropertyMappingList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/RadiusProviderPropertyMapping'
required:
- pagination
- results
PaginatedReputationList:
type: object
properties:
@ -43196,6 +43433,25 @@ components:
delete_token_on_disconnect:
type: boolean
description: When set to true, connection tokens will be deleted upon disconnect.
PatchedRadiusProviderPropertyMappingRequest:
type: object
description: RadiusProviderPropertyMapping Serializer
properties:
managed:
type: string
nullable: true
minLength: 1
title: Managed by authentik
description: Objects that are managed by authentik. These objects are created
and updated automatically. This flag only indicates that an object can
be overwritten by migrations. You can still modify the objects via the
API, but expect changes to be overwritten in a later update.
name:
type: string
minLength: 1
expression:
type: string
minLength: 1
PatchedRadiusProviderRequest:
type: object
description: RadiusProvider Serializer
@ -45329,6 +45585,16 @@ components:
required:
- authorization_flow
- name
RadiusCheckAccess:
type: object
description: Base serializer class which doesn't implement create/update methods
properties:
attributes:
type: string
access:
$ref: '#/components/schemas/PolicyTestResult'
required:
- access
RadiusOutpostConfig:
type: object
description: RadiusProvider Serializer
@ -45453,6 +45719,73 @@ components:
- pk
- verbose_name
- verbose_name_plural
RadiusProviderPropertyMapping:
type: object
description: RadiusProviderPropertyMapping Serializer
properties:
pk:
type: string
format: uuid
readOnly: true
title: Pm uuid
managed:
type: string
nullable: true
title: Managed by authentik
description: Objects that are managed by authentik. These objects are created
and updated automatically. This flag only indicates that an object can
be overwritten by migrations. You can still modify the objects via the
API, but expect changes to be overwritten in a later update.
name:
type: string
expression:
type: string
component:
type: string
description: Get object's component so that we know how to edit the object
readOnly: true
verbose_name:
type: string
description: Return object's verbose_name
readOnly: true
verbose_name_plural:
type: string
description: Return object's plural verbose_name
readOnly: true
meta_model_name:
type: string
description: Return internal model name
readOnly: true
required:
- component
- expression
- meta_model_name
- name
- pk
- verbose_name
- verbose_name_plural
RadiusProviderPropertyMappingRequest:
type: object
description: RadiusProviderPropertyMapping Serializer
properties:
managed:
type: string
nullable: true
minLength: 1
title: Managed by authentik
description: Objects that are managed by authentik. These objects are created
and updated automatically. This flag only indicates that an object can
be overwritten by migrations. You can still modify the objects via the
API, but expect changes to be overwritten in a later update.
name:
type: string
minLength: 1
expression:
type: string
minLength: 1
required:
- expression
- name
RadiusProviderRequest:
type: object
description: RadiusProvider Serializer

View File

@ -87,7 +87,7 @@ class TestProviderRadius(SeleniumTestCase):
srv = Client(
server="localhost",
secret=self.shared_secret.encode(),
dict=Dictionary("tests/radius-dictionary"),
dict=Dictionary("authentik/providers/radius/dictionaries/dictionary"),
)
req = srv.CreateAuthPacket(
@ -109,7 +109,7 @@ class TestProviderRadius(SeleniumTestCase):
srv = Client(
server="localhost",
secret=self.shared_secret.encode(),
dict=Dictionary("tests/radius-dictionary"),
dict=Dictionary("authentik/providers/radius/dictionaries/dictionary"),
)
req = srv.CreateAuthPacket(

View File

@ -3,6 +3,7 @@ import "@goauthentik/admin/property-mappings/PropertyMappingLDAPSourceForm";
import "@goauthentik/admin/property-mappings/PropertyMappingMicrosoftEntraForm";
import "@goauthentik/admin/property-mappings/PropertyMappingNotification";
import "@goauthentik/admin/property-mappings/PropertyMappingRACForm";
import "@goauthentik/admin/property-mappings/PropertyMappingRadiusForm";
import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm";
import "@goauthentik/admin/property-mappings/PropertyMappingSCIMForm";
import "@goauthentik/admin/property-mappings/PropertyMappingScopeForm";

View File

@ -0,0 +1,73 @@
import { BasePropertyMappingForm } from "@goauthentik/admin/property-mappings/BasePropertyMappingForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { docLink } from "@goauthentik/common/global";
import "@goauthentik/elements/CodeMirror";
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { customElement } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { PropertymappingsApi, RadiusProviderPropertyMapping } from "@goauthentik/api";
@customElement("ak-property-mapping-radius-form")
export class PropertyMappingRadiusForm extends BasePropertyMappingForm<RadiusProviderPropertyMapping> {
loadInstance(pk: string): Promise<RadiusProviderPropertyMapping> {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsRadiusRetrieve({
pmUuid: pk,
});
}
async send(data: RadiusProviderPropertyMapping): Promise<RadiusProviderPropertyMapping> {
if (this.instance) {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsRadiusUpdate({
pmUuid: this.instance.pk,
radiusProviderPropertyMappingRequest: data,
});
} else {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsRadiusCreate({
radiusProviderPropertyMappingRequest: data,
});
}
}
renderForm(): TemplateResult {
return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
<input
type="text"
value="${ifDefined(this.instance?.name)}"
class="pf-c-form-control"
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Expression")}
?required=${true}
name="expression"
>
<ak-codemirror
mode=${CodeMirrorMode.Python}
value="${ifDefined(this.instance?.expression)}"
>
</ak-codemirror>
<p class="pf-c-form__helper-text">
${msg("Expression using Python.")}
<a
target="_blank"
rel="noopener noreferrer"
href="${docLink("/docs/property-mappings/expression?utm_source=authentik")}"
>
${msg("See documentation for a list of all variables.")}
</a>
</p>
</ak-form-element-horizontal>`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-property-mapping-radius-form": PropertyMappingRadiusForm;
}
}

View File

@ -2,6 +2,7 @@ import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect";
@ -11,7 +12,35 @@ import { TemplateResult, html } from "lit";
import { ifDefined } from "lit-html/directives/if-defined.js";
import { customElement } from "lit/decorators.js";
import { FlowsInstancesListDesignationEnum, ProvidersApi, RadiusProvider } from "@goauthentik/api";
import {
FlowsInstancesListDesignationEnum,
PropertymappingsApi,
ProvidersApi,
RadiusProvider,
RadiusProviderPropertyMapping,
} from "@goauthentik/api";
export async function radiusPropertyMappingsProvider(page = 1, search = "") {
const propertyMappings = await new PropertymappingsApi(
DEFAULT_CONFIG,
).propertymappingsRadiusList({
ordering: "name",
pageSize: 20,
search: search.trim(),
page,
});
return {
pagination: propertyMappings.pagination,
options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]),
};
}
export function makeRadiusPropertyMappingsSelector(instanceMappings?: string[]) {
const localMappings = instanceMappings ? new Set(instanceMappings) : undefined;
return localMappings
? ([pk, _]: DualSelectPair) => localMappings.has(pk)
: ([_0, _1, _2, _]: DualSelectPair<RadiusProviderPropertyMapping>) => [];
}
@customElement("ak-provider-radius-form")
export class RadiusProviderFormPage extends WithBrandConfig(BaseProviderForm<RadiusProvider>) {
@ -118,6 +147,22 @@ export class RadiusProviderFormPage extends WithBrandConfig(BaseProviderForm<Rad
will be dropped.`)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Property mappings")}
name="propertyMappings"
>
<ak-dual-select-dynamic-selected
.provider=${radiusPropertyMappingsProvider}
.selector=${makeRadiusPropertyMappingsSelector(
this.instance?.propertyMappings,
)}
available-label=${msg("Available Property Mappings")}
selected-label=${msg("Selected Property Mappings")}
></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text">
${msg("Hold control/command to select multiple items.")}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>`;
}