Disable strict realm validation to allow username format user@tenant (non-DNS realm).
This commit is contained in:
@@ -0,0 +1,211 @@
|
|||||||
|
#
|
||||||
|
# Example of forbidding all attempts to login via
|
||||||
|
# realms.
|
||||||
|
#
|
||||||
|
deny_realms {
|
||||||
|
if (&User-Name && (&User-Name =~ /@|\\/)) {
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Filter the username
|
||||||
|
#
|
||||||
|
# Force some sanity on User-Name. This helps to avoid issues
|
||||||
|
# issues where the back-end database is "forgiving" about
|
||||||
|
# what constitutes a user name.
|
||||||
|
#
|
||||||
|
filter_username {
|
||||||
|
if (&User-Name) {
|
||||||
|
#
|
||||||
|
# reject mixed case e.g. "UseRNaMe"
|
||||||
|
#
|
||||||
|
#if (&User-Name != "%{tolower:%{User-Name}}") {
|
||||||
|
# reject
|
||||||
|
#}
|
||||||
|
|
||||||
|
#
|
||||||
|
# reject all whitespace
|
||||||
|
# e.g. "user@ site.com", or "us er", or " user", or "user "
|
||||||
|
#
|
||||||
|
if (&User-Name =~ / /) {
|
||||||
|
update request {
|
||||||
|
&Module-Failure-Message += 'Rejected: User-Name contains whitespace'
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# reject Multiple @'s
|
||||||
|
# e.g. "user@site.com@site.com"
|
||||||
|
#
|
||||||
|
if (&User-Name =~ /@[^@]*@/ ) {
|
||||||
|
update request {
|
||||||
|
&Module-Failure-Message += 'Rejected: Multiple @ in User-Name'
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# reject double dots
|
||||||
|
# e.g. "user@site..com"
|
||||||
|
#
|
||||||
|
if (&User-Name =~ /\.\./ ) {
|
||||||
|
update request {
|
||||||
|
&Module-Failure-Message += 'Rejected: User-Name contains multiple ..s'
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# must have at least 1 string-dot-string after @
|
||||||
|
# e.g. "user@site.com"
|
||||||
|
#
|
||||||
|
# if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/)) {
|
||||||
|
# update request {
|
||||||
|
# &Module-Failure-Message += 'Rejected: Realm does not have at least one dot separator'
|
||||||
|
# }
|
||||||
|
# reject
|
||||||
|
# }
|
||||||
|
|
||||||
|
#
|
||||||
|
# Realm ends with a dot
|
||||||
|
# e.g. "user@site.com."
|
||||||
|
#
|
||||||
|
if (&User-Name =~ /\.$/) {
|
||||||
|
update request {
|
||||||
|
&Module-Failure-Message += 'Rejected: Realm ends with a dot'
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Realm begins with a dot
|
||||||
|
# e.g. "user@.site.com"
|
||||||
|
#
|
||||||
|
if (&User-Name =~ /@\./) {
|
||||||
|
update request {
|
||||||
|
&Module-Failure-Message += 'Rejected: Realm begins with a dot'
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Filter the User-Password
|
||||||
|
#
|
||||||
|
# Some equipment sends passwords with embedded zeros.
|
||||||
|
# This policy filters them out.
|
||||||
|
#
|
||||||
|
filter_password {
|
||||||
|
if (&User-Password && \
|
||||||
|
(&User-Password != "%{string:User-Password}")) {
|
||||||
|
update request {
|
||||||
|
&Tmp-String-0 := "%{string:User-Password}"
|
||||||
|
&User-Password := "%{string:Tmp-String-0}"
|
||||||
|
&Tmp-String-0 !* ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter_inner_identity {
|
||||||
|
#
|
||||||
|
# No names, reject.
|
||||||
|
#
|
||||||
|
if (!&outer.request:User-Name || !&User-Name) {
|
||||||
|
update request {
|
||||||
|
Module-Failure-Message = "User-Name is required for tunneled authentication"
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Do detailed checks only if the inner and outer
|
||||||
|
# NAIs are different.
|
||||||
|
#
|
||||||
|
# If the NAIs are the same, it violates user privacy,
|
||||||
|
# but is allowed.
|
||||||
|
#
|
||||||
|
if (&outer.request:User-Name != &User-Name) {
|
||||||
|
#
|
||||||
|
# Get the outer realm.
|
||||||
|
#
|
||||||
|
if (&outer.request:User-Name =~ /@([^@]+)$/) {
|
||||||
|
update request {
|
||||||
|
Outer-Realm-Name = "%{1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# When we have an outer realm name, the user portion
|
||||||
|
# MUST either be empty, or begin with "anon".
|
||||||
|
#
|
||||||
|
# We don't check for the full "anonymous", because
|
||||||
|
# some vendors don't follow the standards.
|
||||||
|
#
|
||||||
|
if (&outer.request:User-Name !~ /^(anon|@)/) {
|
||||||
|
update request {
|
||||||
|
Module-Failure-Message = "User-Name is not anonymized"
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# There's no outer realm. The outer NAI is different from the
|
||||||
|
# inner NAI. The User-Name MUST be anonymized.
|
||||||
|
#
|
||||||
|
# Otherwise, you could log in as outer "bob", and inner "doug",
|
||||||
|
# and we'd have no idea which one was correct.
|
||||||
|
#
|
||||||
|
elsif (&outer.request:User-Name !~ /^anon/) {
|
||||||
|
update request {
|
||||||
|
Module-Failure-Message = "User-Name is not anonymized"
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the inner realm.
|
||||||
|
#
|
||||||
|
if (&User-Name =~ /@([^@]+)$/) {
|
||||||
|
update request {
|
||||||
|
Inner-Realm-Name = "%{1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Note that we do EQUALITY checks for realm names.
|
||||||
|
# There is no simple way to do case insensitive checks
|
||||||
|
# on internationalized domain names. There is no reason
|
||||||
|
# to allow outer "anonymous@EXAMPLE.COM" and inner
|
||||||
|
# "user@example.com". The user should enter the same
|
||||||
|
# realm for both identities.
|
||||||
|
#
|
||||||
|
# If the inner realm isn't the same as the outer realm,
|
||||||
|
# the inner realm MUST be a subdomain of the outer realm.
|
||||||
|
#
|
||||||
|
if (&Outer-Realm-Name && \
|
||||||
|
(&Inner-Realm-Name != &Outer-Realm-Name) && \
|
||||||
|
(&Inner-Realm-Name !~ /\.%{Outer-Realm-Name}$/)) {
|
||||||
|
update request {
|
||||||
|
Module-Failure-Message = "Inner realm '%{Inner-Realm-Name}' and outer realm '%{Outer-Realm-Name}' are not from the same domain."
|
||||||
|
}
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# It's OK to have an inner realm and no outer realm.
|
||||||
|
#
|
||||||
|
# That won't work for roaming, but the local RADIUS server
|
||||||
|
# can still authenticate the user.
|
||||||
|
#
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# It's OK to have an outer realm and no inner realm.
|
||||||
|
#
|
||||||
|
# It will work for roaming, and the local RADIUS server
|
||||||
|
# can authenticate the user without the realm.
|
||||||
|
#
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{{- /*
|
||||||
|
Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved.
|
||||||
|
SPDX-License-Identifier: APACHE-2.0
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ printf "%s-filter" (include "st-common.names.fullname" .) }}
|
||||||
|
namespace: {{ include "st-common.names.namespace" . | quote }}
|
||||||
|
labels: {{- include "st-common.labels.standard" . | nindent 4 }}
|
||||||
|
{{- if .Values.commonLabels }}
|
||||||
|
{{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.commonAnnotations }}
|
||||||
|
annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
data:
|
||||||
|
{{ (.Files.Glob "files/policy/filter").AsConfig | indent 2 }}
|
||||||
@@ -288,7 +288,10 @@ spec:
|
|||||||
subPath: queries.conf
|
subPath: queries.conf
|
||||||
- name: freeradius-radius-conf
|
- name: freeradius-radius-conf
|
||||||
mountPath: /etc/freeradius/radius.conf
|
mountPath: /etc/freeradius/radius.conf
|
||||||
subPath: radius.conf
|
subPath: radius.conf
|
||||||
|
- name: freeradius-filter
|
||||||
|
mountPath: /etc/freeradius/policy.d/filter
|
||||||
|
subPath: filter
|
||||||
- name: freeradius-sites
|
- name: freeradius-sites
|
||||||
mountPath: /etc/freeradius/sites-enabled/default
|
mountPath: /etc/freeradius/sites-enabled/default
|
||||||
subPath: default
|
subPath: default
|
||||||
@@ -339,7 +342,10 @@ spec:
|
|||||||
name: {{ printf "%s-mods-config" (include "st-common.names.fullname" .) }}
|
name: {{ printf "%s-mods-config" (include "st-common.names.fullname" .) }}
|
||||||
- name: freeradius-radius-conf
|
- name: freeradius-radius-conf
|
||||||
configMap:
|
configMap:
|
||||||
name: {{ printf "%s-radius-conf" (include "st-common.names.fullname" .) }}
|
name: {{ printf "%s-radius-conf" (include "st-common.names.fullname" .) }}
|
||||||
|
- name: freeradius-filter
|
||||||
|
configMap:
|
||||||
|
name: {{ printf "%s-filter" (include "st-common.names.fullname" .) }}
|
||||||
- name: temp
|
- name: temp
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
- name: shared-certs
|
- name: shared-certs
|
||||||
|
|||||||
Reference in New Issue
Block a user