The past two weeks I’ve been looking into getting a juniper SA 4500 to work with Radiator to do two-factor authentication by using One-Time Passwords (OTP). Basicly, after user authentication is done against a Directory Server (DS), I want Radiator to lookup the user’s mobile number in the DS, create an One-Time Password and SMS this password to the user’s mobile phone.
Although Radiator can handle OTP, the AuthOTP.pm module that comes with Radiator isn’t sufficient to work directly with the Juniper. This is why I had to make a few changes to the original AuthOTP.pm module. Download the patch here.
In the configuration file below, you see an example on how to use the module.
# radius.cfg - Niels van Sluis, <niels@van-sluis.nl>
#
# Example Radiator configuration file.
#
# * retrieve mobile number from Directory Server.
# * generate and send One-Time Password to mobile number.
# * authenticate One-Time Password.
LogDir /var/log/radius
DbDir /etc/radiator
# User a lower trace level in production systems:
Trace 7
AuthPort 1812
AcctPort 1813
<Client juni-sslvpn.example.com>
Secret mysecret
Identifier juni-sslvpn
</Client>
<AuthBy LDAP2>
# Radiator talks to Microsoft AD.
# Try to find mobile number only.
Identifier SSLVPN_LDAP
Host ldap.example.com
BaseDN OU=employees,DC=example,DC=com
AuthDN CN=srv_juniper,OU=Service Accounts,DC=example,DC=com
AuthPassword *****
HoldServerConnection
Timeout 2
UsernameAttr sAMAccountName
# Get attribute that contains the mobile number.
AuthAttrDef MobileNumber
# We don't do authentication. Authentication is done by OTP.
NoCheckPassword
# Some code to put the mobile number into memory, so it can be used
# by OTP.
PostSearchHook sub {\
use Radius::Context;\
my $user = $_[1];\
my $attr = ($_[4]->get('MobileNumber'))[0];\
my $context = &Radius::Context::get("otp:$user", 120);\
$context->{mobile_number} = $attr;\
}
</AuthBy>
<AuthBy OTP>
# Authenticate based on One-Time Password sent to user by SMS.
Identifier SSLVPN_OTP
EAPType One-Time-Password,Generic-Token
ChallengeHook sub {my ($self, $user, $p, $context) = @_;\
$context->{otp_password} = $self->generate_password();\
system('/etc/radiator/otp/sendsms.php', $user, $context->{mobile_number}, $context->{otp_password});\
return "Enter One-Time Password"; \
}
</AuthBy>
<AuthBy GROUP>
Identifier Check-LDAP-and-OTP
AuthByPolicy ContinueWhileAccept
AuthBy SSLVPN_LDAP
AuthBy SSLVPN_OTP
</AuthBY>
<Handler Client-Identifier = juni-sslvpn>
RejectHasReason
AuthBy Check-LDAP-and-OTP
</Handler> |
Click here to download radius.cfg
Configure the Juniper SA 4500
Configuring two-factor authentication on the Juniper is really easy. When creating an user realm, you can choose to use an additional authentication server. So I configured two authentication servers. The first one authenticates against the Directory Server. The second authentication server uses radius to authenticate against Radiator. It will prompt the user to enter the One-Time Password.
Configure the additional Authentication Server
Create a new authentication server that uses RADIUS. Most important here are the ‘Custom Radius Rules’.
Custom Radius Rules
The custom radius rules define how the Juniper talks with Radiator.
Rule 1
Here we define that the Juniper expects a challenge from Radiator and makes sure the user will be prompted with a page where he can enter the password that was send to the user’s mobile phone.
Rule 2
This rule defines what to do if the password entered by the user is rejected by Radiator. It will show the reason why the password was rejected.
Configure an User-Realm
The screen below shows how easy it is to create an user realm that uses an additional authentication server. Make sure the session is ended when authentication to the additional authentication server fails.
Well, I hope this document will save you some time and money in setting up two-factor authentication on the Juniper SA 4500. Enjoy