Embedded Radius Server in Keycloak SSO
Run radius server inside keycloak. features:
- Embedded radius server in keycloak
- radius oidc password
- radius OTP password (TOTP/HOTP via Google Authenticator or FreeOTP)
- use Keycloak user password, if radius access-request protocol is PAP. Otherwise is using radius-password credential or OTP
- use Kerberos credential(only if Radius client use PAP authorization)
- can work as radius proxy
- support Radsec Protocol (Radius over TLS)
- Map Keycloak authorization , Role, Group and User Attributes to Radius Attributes
- conditional attributes for authorization/Role/Group/User
- reject attribute for authorization/Role/Group/User
- dynamically assign attributes based on keycloak policies(Role, javascript, Time, User)
- start/stop Keycloak Session
- BackChannel logout(Disconnect-message request)
- Mikrotik plugin
- Cisco plugin (thanks vbkunin
- Social Hotspot Login
- Assign attributes dynamically using javascript policy
- Reject and Accept condition example
- Radius and OIDC integration example
- OTP Password example
- Default Realm example(if the radius client does not support realm attribute)
- Download keycloak-radius.zip asset from github releases
- unzip release
unzip keycloak-radius.zip -d keycloak-radius
- run keycloak
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
- open http://localhost:8090
- initialize keycloak master realm
requirements: java jdk 11 and above, maven 3.5 and above
-
cd keycloak-plugins
-
mvn clean install
requirements: keycloak 11.0.1
- setup radius-plugin
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.radius --resources=${SOURCE}/keycloak-plugins/radius-plugin/target/radius-plugin-1.2.7-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.apache.commons.io,javax.activation.api,javax.servlet.api,org.jboss.resteasy.resteasy-jaxrs,javax.ws.rs.api,com.fasterxml.jackson.core.jackson-databind,org.keycloak.keycloak-common,com.fasterxml.jackson.core.jackson-core,javax.transaction.api,org.hibernate,io.netty,org.slf4j,javax.xml.bind.api,org.apache.commons.codec"
- setup rad-sec plugin
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.rad.sec --resources=${SOURCE}/keycloak-plugins/rad-sec-plugin/target/rad-sec-plugin-1.2.7-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.apache.commons.io,javax.activation.api,com.fasterxml.jackson.core.jackson-databind,org.keycloak.keycloak-common,com.fasterxml.jackson.core.jackson-core,javax.transaction.api,org.hibernate,io.netty,org.slf4j,javax.xml.bind.api,org.apache.commons.codec,keycloak.plugins.radius"
- setup mikrotik plugin
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.radius.mikrotik --resources=${SOURCE}/keycloak-plugins/mikrotik-radius-plugin/target/mikrotik-radius-plugin-1.2.7-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.apache.commons.io,javax.activation.api,com.fasterxml.jackson.core.jackson-databind,org.keycloak.keycloak-common,com.fasterxml.jackson.core.jackson-core,javax.transaction.api,org.hibernate,io.netty,org.slf4j,javax.xml.bind.api,org.apache.commons.codec,keycloak.plugins.radius"
- setup cisco plugin
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.radius.cisco --resources=${SOURCE}/keycloak-plugins/cisco-radius-plugin/target/cisco-radius-plugin-1.2.7-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.apache.commons.io,javax.activation.api,com.fasterxml.jackson.core.jackson-databind,org.keycloak.keycloak-common,com.fasterxml.jackson.core.jackson-core,javax.transaction.api,org.hibernate,io.netty,org.slf4j,javax.xml.bind.api,org.apache.commons.codec,keycloak.plugins.radius"
- setup chillispot plugin
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.radius.chillispot --resources=${SOURCE}/keycloak-plugins/chillispot-radius-plugin/target/chillispot-radius-plugin-1.2.7-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.apache.commons.io,javax.activation.api,com.fasterxml.jackson.core.jackson-databind,org.keycloak.keycloak-common,com.fasterxml.jackson.core.jackson-core,javax.transaction.api,org.hibernate,io.netty,org.slf4j,javax.xml.bind.api,org.apache.commons.codec,keycloak.plugins.radius"
- setup radius-disconnect plugin
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.radius.dm --resources=${SOURCE}/keycloak-plugins/radius-disconnect-plugin/target/radius-disconnect-plugin-1.2.7-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.apache.commons.io,javax.activation.api,com.fasterxml.jackson.core.jackson-databind,org.keycloak.keycloak-common,com.fasterxml.jackson.core.jackson-core,javax.transaction.api,org.hibernate,io.netty,org.slf4j,javax.xml.bind.api,org.apache.commons.codec,keycloak.plugins.radius,org.keycloak.keycloak-model-jpa,javax.persistence.api,org.hibernate"
- setup proxy-radius plugin
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.radius.proxy --resources=${SOURCE}/keycloak-plugins/proxy-radius-plugin/target/proxy-radius-plugin-1.2.7-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,org.apache.commons.io,javax.activation.api,com.fasterxml.jackson.core.jackson-databind,org.keycloak.keycloak-common,com.fasterxml.jackson.core.jackson-core,javax.transaction.api,org.hibernate,io.netty,org.slf4j,javax.xml.bind.api,org.apache.commons.codec,keycloak.plugins.radius"
- setup radius theme
${KEYCLOAK_PATH}/bin/jboss-cli.sh --command="module add --name=keycloak.plugins.radius.theme --resources=${SOURCE}/keycloak-radius-plugin/keycloak-plugins/radius-theme/target/radius-theme-1.2.7-SNAPSHOT.zip
- run script for standalone
${KEYCLOAK_PATH}/bin/jboss-cli.sh --file=${SOURCE}/cli/radius.cli
- run script for standalone-ha where
${KEYCLOAK_PATH}/bin/jboss-cli.sh --file=${SOURCE}/cli/radius-ha.cli
- KEYCLOAK_PATH - Path where you are unpacked keycloak-10.0.0.zip
- SOURCE - Path where you checked out the code and built the project
-
create file ${KEYCLOAK_PATH}config/radius.config
-
example
where{ "sharedSecret": "radsec", "authPort": 1812, "accountPort": 1813, "numberThreads": 8, "useUdpRadius": true, "radsec": { "privateKey": "config/private.key", "certificate": "config/public.crt", "numberThreads": 8, "useRadSec": true }, "coa":{ "port":3799, "useCoA":true } }
-
sharedSecret - Used to secure communication between a RADIUS server and a RADIUS client.
-
authPort - Authentication and authorization port
-
accountPort - Accounting port
-
useUdpRadius - if true, then listen to authPort and accountPort
-
radsec - radsec configuration
-
privateKey - private SSL key (https://netty.io/wiki/sslcontextbuilder-and-private-key.html)
-
certificate - certificates chain
-
useRadSec - if true, then listen radsec port
-
numberThreads - number of connection threads
-
coa - CoA request configuration
-
port - CoA port (Mikrotik:3799, Cisco:1700)
-
useCoA - use CoA request
Run Keycloak Locally
#!/usr/bin/env bash
set -e
cd keycloak-10.0.0
public_ip=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' -m 1`
sh bin/standalone.sh -c standalone-ha.xml -b 0.0.0.0 -Djboss.bind.address.management=0.0.0.0 -Djboss.bind.address.private=${public_ip} -Djboss.node.name=${public_ip} -Djgroups.bind.address=${public_ip} --debug 8190 -Djboss.http.port=8090
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
COND_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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.
Role REJECT Attributes (Example)
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
REJECT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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"
Role ACCEPT Attributes (Example)
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
ACCEPT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
COND_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
REJECT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
ACCEPT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
COND_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
REJECT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
ACCEPT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
COND_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
REJECT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
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:
<PREFIX><ATTRIBUTE_NAME>=<values>
- PREFIX =
ACCEPT_
- ATTRIBUTE_NAME attribute name from access-request
- VALUES Comma-separated list of attribute values
Example: Role ACCEPT Attributes