Run radius server inside keycloak. features:
unzip keycloak-radius.zip -d keycloak-radius</pre>
sh keycloak-radius/bin/standalone.sh -c standalone.xml -b 0.0.0.0 -Djboss.bind.address.management=0.0.0.0 --debug 8190 -Djboss.http.port=8090</pre>
requirements: java jdk 21 and above, maven 3.9 and above
cd keycloak-plugins
mvn clean install
requirements: keycloak 26.2.5
cp ${SOURCE}/keycloak-plugins/radius-plugin/target/radius-plugin-*.jar \
${SOURCE}/keycloak-plugins/rad-sec-plugin/target/rad-sec-plugin-*.jar \
${SOURCE}/keycloak-plugins/mikrotik-radius-plugin/target/mikrotik-radius-plugin-*.jar \
${SOURCE}/keycloak-plugins/cisco-radius-plugin/target/cisco-radius-plugin-*.jar \
${SOURCE}/keycloak-plugins/chillispot-radius-plugin/target/chillispot-radius-plugin-*.jar \
${SOURCE}/keycloak-plugins/radius-disconnect-plugin/target/radius-disconnect-plugin-*.jar \
${SOURCE}/keycloak-plugins/proxy-radius-plugin/target/proxy-radius-plugin-*.jar \
${SOURCE}/keycloak-radius-plugin/keycloak-plugins/radius-theme/target/radius-theme-*.zip \
${KEYCLOAK_PATH}/providers/
where
Variable Name | Variable Value | Config file Location |
---|---|---|
KEYCLOAK_PATH | Path where you are unpacked keycloak | ${KEYCLOAK_PATH}/config/radius.config |
RADIUS_CONFIG_PATH | Path where you store radius.config | ${RADIUS_CONFIG_PATH}/radius.config |
Examples:
export RADIUS_CONFIG_PATH= /opt/keycloak/radius/config
or
export KEYCLOAK_PATH= /opt/keycloak/
requirements: java jdk 21 and above, maven 3.9 and above, bash, GIT repo checked out
keycloak/init.sh
- downloads the current Keycloak releasekeycloak/build.sh
- cleans, builds and installs the development Keycloak with radius-plugin(s)keycloak/buildAndStart.sh
- calls build.sh and start.shkeycloak/buildAndStartDb.sh
- calls build.sh, restores your saved db etc. and calls start.shkeycloak/start.sh
- starts the development Keycloakkeycloak/saveDb.sh
- saves a copy your db/realms, config, additional plugins/themesDuring development, you usually use buildAndStartDb.sh
, test some stuff, kill your Keycloak and saveDb.sh
.
Change the radius-plugin code and start again with: buildAndStartDb.sh
, …
${KEYCLOAK_PATH}config/radius.config
or ${RADIUS_CONFIG_PATH}/radius.config
{
"sharedSecret": "radsec",
"authPort": 1812,
"accountPort": 1813,
"numberThreads": 8,
"useUdpRadius": true,
"externalDictionary": "/opt/dictionary",
"otpWithoutPassword": [ ],
"radsec": {
"privateKey": "config/private.key",
"certificate": "config/public.crt",
"numberThreads": 8,
"useRadSec": true
},
"coa":{
"port":3799,
"useCoA":true
}
}
where
"otpWithoutPassword": [ "chap", "mschapv2", "pap" ]
"otp":true
is interpreted for backward compatibility as "otpWithoutPassword": [ "chap", "mschapv2" ]
cd keycloak-26.2.5
sh bin/kc.sh --debug 8190 start-dev --http-port=8090 --features-disabled=organization
Radius Protocol | Keycloak credentials | Keycloak credentials with OTP | Kerberos credentials | LDAP credentials | Keycloak Radius credentials | Keycloak Radius credentials with OTP | Keycloak OTP without password |
---|---|---|---|---|---|---|---|
PAP | Yes | Yes | Yes | Yes | Yes | Yes | Yes *1 |
CHAP | No | No | No | No | Yes | Yes | Yes |
MSCHAPV2 | No | No | No | No | Yes | Yes | Yes |
*1) In contrast to CHAP and MSCHAPV2, an OTP token must be registered with the account for PAP and OTP without a password. This prevents authentication from being successful with the password only, even if the user does not yet have a token. An OTP token code is always required as a second factor (password plus code or code without password).
NOTE: Composite roles supported
if conditional Attribute is present and has valid value then all other attributes will be applied. (Example: apply role attributes only if NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example:
COND_NAS-IP-Address = "192.168.88.1, 192.168.88.2"
The role will only be applied if the NAS server address is 192.168.88.1 or 192.168.88.2.
if reject Attribute is present and has valid value then access request will be rejected. (Example: reject user request if access request contains attribute NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example:
REJECT_NAS-IP-Address = "192.168.88.2"
The role will only be applied if the NAS server address is not 192.168.88.2, otherwise request will be rejected
If Reject Attribute is present then access request will be rejected.
Structure of Attribute: REJECT_RADIUS=<ANY VALUE>
Example:
REJECT_RADIUS = "true"
if accept Attribute is present and has valid value then access request will be accepted, otherwise rejected. (Example: accept user request if access request contains attribute NAS-IP-Address= 192.168.88.1,192.168.88.2)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example:
ACCEPT_NAS-IP-Address = "192.168.88.1"
The role will only be applied if the NAS server address is not 192.168.88.2, otherwise request will be rejected
NOTE: SubGroups supported
Group Conditional Attributes
if conditional Attribute is present and has valid value then all other attributes will be applied. (Example: apply group attributes only if NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role Conditional Attributes/README.md:1
if reject Attribute is present and has valid value then access request will be rejected. (Example: reject user request if access request contains attribute NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role REJECT Attributes
If Reject Attribute is present then access request will be rejected.
Structure of Attribute: REJECT_RADIUS=<ANY VALUE>
Example:
REJECT_RADIUS = "true"
if accept Attribute is present and has valid value then access request will be accepted, otherwise rejected. (Example: accept user request if access request contains attribute NAS-IP-Address= 192.168.88.1,192.168.88.2)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role ACCEPT Attributes
if conditional Attribute is present and has valid value then all other attributes will be applied. (Example: apply user attributes only if NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role Conditional Attributes/README.md:1
if reject Attribute is present and has valid value then access request will be rejected. (Example: reject user request if access request contains attribute NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role REJECT Attributes
if accept Attribute is present and has valid value then access request will be accepted, otherwise rejected. (Example: accept user request if access request contains attribute NAS-IP-Address= 192.168.88.1,192.168.88.2)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role ACCEPT Attributes
if conditional Attribute is present and has valid value then all other attributes will be applied. (Example: apply user attributes only if NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role Conditional Attributes/README.md:1
if reject Attribute is present and has valid value then access request will be rejected. (Example: reject user request if access request contains attribute NAS-IP-Address= 192.168.88.1)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role REJECT Attributes
If Reject Attribute is present then access request will be rejected.
Structure of Attribute: REJECT_RADIUS=<ANY VALUE>
Example:
REJECT_RADIUS = "true"
if accept Attribute is present and has valid value then access request will be accepted, otherwise rejected. (Example: accept user request if access request contains attribute NAS-IP-Address= 192.168.88.1,192.168.88.2)
Structure of Attribute: <pre><PREFIX><ATTRIBUTE_NAME>=<values></pre>
Example: Role ACCEPT Attributes
Hotspot Example (with Facebook login)
<Keycloak Password/RADIUS Password><OTP>
,
example: testPassword123456, where testPassword is password, 123456 is OTP<RADIUS Password><OTP>
,
example: testPassword123456, where testPassword is password, 123456 is OTP"otpWithoutPassword": [ "pap", ... ]
): <OTP>
or <RADIUS Password/Keycloak Password/RADIUS Password><OTP>
,
example: 123456, where 123456 is OTP"otpWithoutPassword": [ "chap", "mschapv2", ... ]
): <OTP>
or <RADIUS Password><OTP>
or <RADIUS Password>
if no OTP token is registered,
example: 123456, where 123456 is OTPVENDORATTR 12356 Fortinet-Group-Name 1 string VENDORATTR 12356 Fortinet-Client-IP-Address 2 ipaddr VENDORATTR 12356 Fortinet-Vdom-Name 3 string VENDORATTR 12356 Fortinet-Client-IPv6-Address 4 octets VENDORATTR 12356 Fortinet-Interface-Name 5 string VENDORATTR 12356 Fortinet-Access-Profile 6 string
- run as docker container
docker run -p 8090:8080 -e -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true” -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -e RADIUS_DICTIONARY=/opt/dictionary -v pwd
/Fortinet.dictionary:/opt/dictionary vassio/keycloak-radius-plugin
```