Embedded Radius Server in Keycloak SSO
Run radius server inside keycloak. features:
- Embedded radius server in keycloak
- use keycloak authentication and authorization for the embedded RADIUS server
- radius oidc password
- radius OTP password (TOTP/HOTP via Google Authenticator or FreeOTP)
- use Keycloak user credentials, if radius access-request protocol is PAP Otherwise is using Keycloak Radius credentials or OTP
- use Kerberos/ldap credentials(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)
- Service to Service communication
- Mikrotik plugin
- Cisco plugin (thanks vbkunin)
- Chillispot plugin
- Social Hotspot Login
- PPTP VPN with Radsec
- L2TP IPSec VPN with Radius and Radsec
- Assign attributes dynamically using javascript policy
- Reject and Accept condition example
- Radius and OIDC integration example
- OTP Password example
- Specify Realm in username: username@realm
- Default Realm example(if the radius client does not support realm attribute)
- An example of a call from backend service to radius using a service account (Service to Service communication)
- 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 13.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.3.8-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,org.apache.commons.lang3"
- 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.3.8-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.apache.commons.lang3"
- 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.3.8-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.apache.commons.lang3"
- 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.3.8-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.apache.commons.lang3"
- 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.3.8-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.apache.commons.lang3"
- 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.3.8-SNAPSHOT.jar --dependencies=org.jboss.logging,org.keycloak.keycloak-core,javax.ws.rs.api,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,org.apache.commons.lang3"
- 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.3.8-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.apache.commons.lang3"
- 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.3.8-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-13.0.1.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, "otp": false, "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
-
otp - use OTP without password
Run Keycloak Locally
#!/usr/bin/env bash
set -e
cd keycloak-13.0.1
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
Radius Protocol | Keycloak credentials | Keycloak credentials with OTP | Kerberos credentials | Ldap credentials | Keycloak Radius credentials | Keycloak Radius credentials with OTP | Keycloak OTP(if config file contains "otp":true) |
---|---|---|---|---|---|---|---|
PAP | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
CHAP | No | No | No | No | Yes | Yes | Yes |
MSCHAPV2 | No | No | No | No | Yes | Yes | Yes |
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
Hotspot Example (with Facebook login)
- Setup Radius Credentials during first time login
- enable Otp Password on Keycloak side. https://www.keycloak.org/docs/latest/server_admin/
- password in request must contain the password and otp.
- Structure Password in request:
- PAP password:
<Keycloak Password/RADIUS Password><OTP>
example: testPassword123456, where testPassword is password, 123456 is otp - MSCHAP/CHAP:
<RADIUS Password><OTP>
example: testPassword123456, where testPassword is password, 123456 is otp - PAP password with Otp (if config file contains "otp":true) :
<OTP>
example: 123456, where 123456 is otp
- PAP password: