Privacyidea + radius + fortigate

Hello,
I would like to link privacyidea and VPN Fortigate with each other. I have set up a radius server on a privacyidea server. I did everything as in the guide: error509.com/2020/05/fortigate-2fa-con-freeradius-y-privacyidea/ When logging into fortigate, the user enters his password and logs in without entering the token required. In debug mode on radius I have this message:

(0) Received Access-Request Id 187 from 10.200.1.254:24054 to 172.20.17.171:1812 length 136
(0) NAS-Identifier = “eulc”
(0) User-Name = “testoweradius”
(0) User-Password = “XXX”
(0) NAS-IP-Address = 10.200.1.254
(0) NAS-Port = 1
(0) NAS-Port-Type = Virtual
(0) Called-Station-Id = “10.200.1.254”
(0) Calling-Station-Id = “172.20.20.10”
(0) Acct-Session-Id = “49df5f47”
(0) Connect-Info = “vpn-ssl”
(0) Fortinet-Vdom-Name = “root”
(0) # Executing section authorize from file /etc/freeradius/3.0/sites-enabled/privacyidea
(0) authorize {
(0) perl-privacyidea: $RAD_REQUEST{‘User-Name’} = &request:User-Name -> ‘testoweradius’
(0) perl-privacyidea: $RAD_REQUEST{‘User-Password’} = &request:User-Password -> ‘XXX’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-IP-Address’} = &request:NAS-IP-Address -> ‘10.200.1.254’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-Port’} = &request:NAS-Port -> ‘1’
(0) perl-privacyidea: $RAD_REQUEST{‘Called-Station-Id’} = &request:Called-Station-Id -> ‘10.200.1.254’
(0) perl-privacyidea: $RAD_REQUEST{‘Calling-Station-Id’} = &request:Calling-Station-Id -> ‘172.20.20.10’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-Identifier’} = &request:NAS-Identifier -> ‘eulc’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-Port-Type’} = &request:NAS-Port-Type -> ‘Virtual’
(0) perl-privacyidea: $RAD_REQUEST{‘Acct-Session-Id’} = &request:Acct-Session-Id -> ‘49df5f47’
(0) perl-privacyidea: $RAD_REQUEST{‘Connect-Info’} = &request:Connect-Info -> ‘vpn-ssl’
(0) perl-privacyidea: $RAD_REQUEST{‘Fortinet-Vdom-Name’} = &request:Fortinet-Vdom-Name -> ‘root’
(0) perl-privacyidea: &request:NAS-Identifier = $RAD_REQUEST{‘NAS-Identifier’} -> ‘eulc’
(0) perl-privacyidea: &request:Calling-Station-Id = $RAD_REQUEST{‘Calling-Station-Id’} -> ‘172.20.20.10’
(0) perl-privacyidea: &request:Fortinet-Vdom-Name = $RAD_REQUEST{‘Fortinet-Vdom-Name’} -> ‘root’
(0) perl-privacyidea: &request:Called-Station-Id = $RAD_REQUEST{‘Called-Station-Id’} -> ‘10.200.1.254’
(0) perl-privacyidea: &request:Connect-Info = $RAD_REQUEST{‘Connect-Info’} -> ‘vpn-ssl’
(0) perl-privacyidea: &request:NAS-Port-Type = $RAD_REQUEST{‘NAS-Port-Type’} -> ‘Virtual’
(0) perl-privacyidea: &request:Acct-Session-Id = $RAD_REQUEST{‘Acct-Session-Id’} -> ‘49df5f47’
(0) perl-privacyidea: &request:User-Password = $RAD_REQUEST{‘User-Password’} -> ‘XXX’
(0) perl-privacyidea: &request:NAS-IP-Address = $RAD_REQUEST{‘NAS-IP-Address’} -> ‘10.200.1.254’
(0) perl-privacyidea: &request:NAS-Port = $RAD_REQUEST{‘NAS-Port’} -> ‘1’
(0) perl-privacyidea: &request:User-Name = $RAD_REQUEST{‘User-Name’} -> ‘testoweradius’
(0) [perl-privacyidea] = ok
(0) if (ok || updated) {
(0) if (ok || updated) -> TRUE
(0) if (ok || updated) {
(0) update control {
(0) Auth-Type := Perl
(0) } # update control = noop
(0) } # if (ok || updated) = noop
(0) } # authorize = ok
(0) Found Auth-Type = Perl
(0) # Executing group from file /etc/freeradius/3.0/sites-enabled/privacyidea
(0) Auth-Type Perl {
(0) perl-privacyidea: $RAD_REQUEST{‘User-Name’} = &request:User-Name -> ‘testoweradius’
(0) perl-privacyidea: $RAD_REQUEST{‘User-Password’} = &request:User-Password -> ‘XXX’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-IP-Address’} = &request:NAS-IP-Address -> ‘10.200.1.254’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-Port’} = &request:NAS-Port -> ‘1’
(0) perl-privacyidea: $RAD_REQUEST{‘Called-Station-Id’} = &request:Called-Station-Id -> ‘10.200.1.254’
(0) perl-privacyidea: $RAD_REQUEST{‘Calling-Station-Id’} = &request:Calling-Station-Id -> ‘172.20.20.10’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-Identifier’} = &request:NAS-Identifier -> ‘eulc’
(0) perl-privacyidea: $RAD_REQUEST{‘NAS-Port-Type’} = &request:NAS-Port-Type -> ‘Virtual’
(0) perl-privacyidea: $RAD_REQUEST{‘Acct-Session-Id’} = &request:Acct-Session-Id -> ‘49df5f47’
(0) perl-privacyidea: $RAD_REQUEST{‘Connect-Info’} = &request:Connect-Info -> ‘vpn-ssl’
(0) perl-privacyidea: $RAD_REQUEST{‘Fortinet-Vdom-Name’} = &request:Fortinet-Vdom-Name -> ‘root’
(0) perl-privacyidea: $RAD_CHECK{‘Auth-Type’} = &control:Auth-Type -> ‘Perl’
(0) perl-privacyidea: $RAD_CONFIG{‘Auth-Type’} = &control:Auth-Type -> ‘Perl’
rlm_perl: Config File /etc/privacyidea/rlm_perl.ini found!
rlm_perl: Debugging config:
rlm_perl: Default URL
rlm_perl: Looking for config for auth-type Perl
rlm_perl: Auth-Type: Perl
rlm_perl: url:
rlm_perl: user sent to privacyidea: testoweradius
rlm_perl: realm sent to privacyidea:
rlm_perl: resolver sent to privacyidea:
rlm_perl: client sent to privacyidea: 10.200.1.254
rlm_perl: state sent to privacyidea:
rlm_perl: urlparam client
rlm_perl: urlparam user
rlm_perl: urlparam pass
rlm_perl: Request timeout: 10
rlm_perl: Not verifying SSL certificate!
rlm_perl: elapsed time for privacyidea call: 0.316801
rlm_perl: privacyIDEA Result status is true!
rlm_perl: ++++ Parsing group: Attribute
rlm_perl: +++++ Found member ‘Attribute Filter-Id’
rlm_perl: ++++++ Attribute: IF ‘’->’’ == ‘’ THEN ‘Filter-Id’
rlm_perl: ++++++ no directory
rlm_perl: +++++++ User attribute is a string:
rlm_perl: +++++++ trying to match
rlm_perl: ++++++++ Result: No match, no RADIUS attribute Filter-Id added.
rlm_perl: +++++ Found member ‘Attribute otherAttribute’
rlm_perl: ++++++ Attribute: IF ‘’->’’ == ‘’ THEN ‘otherAttribute’
rlm_perl: ++++++ no directory
rlm_perl: +++++++ User attribute is a string:
rlm_perl: +++++++ trying to match
rlm_perl: ++++++++ Result: No match, no RADIUS attribute otherAttribute added.
rlm_perl: +++++ Found member ‘Attribute Class’
rlm_perl: ++++++ Attribute: IF ‘’->’’ == ‘’ THEN ‘Class’
rlm_perl: ++++++ no directory
rlm_perl: +++++++ User attribute is a string:
rlm_perl: +++++++ trying to match
rlm_perl: ++++++++ Result: No match, no RADIUS attribute Class added.
rlm_perl: ++++ Parsing group: Mapping
rlm_perl: +++++ Found member ‘Mapping user’
rlm_perl: return RLM_MODULE_HANDLED
(0) perl-privacyidea: &request:NAS-Identifier = $RAD_REQUEST{‘NAS-Identifier’} -> ‘eulc’
(0) perl-privacyidea: &request:Calling-Station-Id = $RAD_REQUEST{‘Calling-Station-Id’} -> ‘172.20.20.10’
(0) perl-privacyidea: &request:Fortinet-Vdom-Name = $RAD_REQUEST{‘Fortinet-Vdom-Name’} -> ‘root’
(0) perl-privacyidea: &request:Called-Station-Id = $RAD_REQUEST{‘Called-Station-Id’} -> ‘10.200.1.254’
(0) perl-privacyidea: &request:Connect-Info = $RAD_REQUEST{‘Connect-Info’} -> ‘vpn-ssl’
(0) perl-privacyidea: &request:NAS-Port-Type = $RAD_REQUEST{‘NAS-Port-Type’} -> ‘Virtual’
(0) perl-privacyidea: &request:Acct-Session-Id = $RAD_REQUEST{‘Acct-Session-Id’} -> ‘49df5f47’
(0) perl-privacyidea: &request:User-Password = $RAD_REQUEST{‘User-Password’} -> ‘XXX’
(0) perl-privacyidea: &request:NAS-IP-Address = $RAD_REQUEST{‘NAS-IP-Address’} -> ‘10.200.1.254’
(0) perl-privacyidea: &request:NAS-Port = $RAD_REQUEST{‘NAS-Port’} -> ‘1’
(0) perl-privacyidea: &request:User-Name = $RAD_REQUEST{‘User-Name’} -> ‘testoweradius’
(0) perl-privacyidea: &reply:State = $RAD_REPLY{‘State’} -> ‘15449381172582708956’
(0) perl-privacyidea: &reply:Reply-Message = $RAD_REPLY{‘Reply-Message’} -> 'please enter otp: ’
(0) perl-privacyidea: &control:Auth-Type = $RAD_CHECK{‘Auth-Type’} -> ‘Perl’
(0) perl-privacyidea: &control:Response-Packet-Type = $RAD_CHECK{‘Response-Packet-Type’} -> ‘Access-Challenge’
(0) [perl-privacyidea] = handled
(0) } # Auth-Type Perl = handled
(0) Using Post-Auth-Type Challenge
(0) Post-Auth-Type sub-section not found. Ignoring.
(0) Sent Access-Challenge Id 187 from 172.20.17.171:1812 to 10.200.1.254:24054 length 0
(0) State = 0x3135343439333831313732353832373038393536
(0) Reply-Message = "please enter otp: "
(0) Finished request
Waking up in 4.9 seconds.
(0) Cleaning up request packet ID 187 with timestamp +15

Did you configure a policy like in this image?

If so, selecting user store for the otppin instructs PrivacyIDEA to use the password from your userstore, that is, use the password from Active Directory. Uncheck that option and PrivacyIDEA will check the password field value against the tokens assigned to the user.

I’ve double-checked my installation and configuration against that guide and, other than the one setting mentioned above, it’s identical. So, I don’t know how the guide’s author is getting a second window prompting for OTP. There’s a lot of configuration that seems to be missing from the guide for both systems as well.

The authentication flow in my setup is, in my opinion, better than provided in the guide as it doesn’t require the user to enter their AD credentials. The user enters their AD username and then their OTP+PIN for the password.

The guide also omits configuring a policy to forward user information in the radius response. This policy, coupled with proper rlm_perl.ini configuration, is incredibly beneficial with a Fortigate. With it configured this way, the Fortigate can process policies based on the user’s AD group membership.

The only thing is that I want to log in with AD credentials and then with a token. When I checked “userstore” I can still log in with AD credentials or a token. I wish there were both, one after the other.

I have a privacyIdea solution with freeradius up and running. So far I have 4 different ldap resolvers configured and several Fortigates using radius against the freeradius. There is no problem getting the second OTP window when using VPN.
What’s important is to have the correct policies on PrivacyIdea
Create a policy to use LDAP password as token pin.
be sure to define the policy in a such matter that it will hit the user logins from the Fortigate.
P3a_Policy-1
Use Scope=Authentication
Under additional conditions you can specify gruop the user needs to be member of.
P3a_Policy-2
You dont need alle the actions i’ve used. otppin = userstore makes the system use LDAP password as pin.
P3a_Policy-3

On the Fortigate. Configure your radius setting.
P3a_FG-1
and the usergroup
P3a_FG-2

Then configure your VPN setting an policy refering to this usergroup.

Thart should be it all, it works fine both using SSL VPN web portal and the client
P3a_FG-3

I set the configuration as you provided. Unfortunately, the user can log in with his password or token (there is no double authentication). Do I need to configure the radius server in the privacyidea GUI:
image

What are your settings in Additional Conditions: https://community.privacyidea.org/uploads/default/original/2X/9/9d00df9775e2f0941c53da7e2749f41d4a9f4fb8.png

Have you setup anything in the rlm_perl.ini files?

In this place:
https://community.privacyidea.org/uploads/default/original/2X/3/399d442f2e2fa728d8c1201a448ce862754be77b.png

server radius is the address of the server fortigate? which I entered in clients.conf on the radius server?
primary server is the radius server address?

privacyIDEA and the FreeRADIUS acts correct.
They send back a Access-Challenge.

This is a RADIUS packet that is ment to tell the Fortigate “The user is not completely authenticated, yet”.

If the Fortigate would in turn act correctly, then it should display the Reply-Message: “Please enter your otp:”.

If your Fortigate does not do this, there is something wrong with your Fortigate.

1 Like

What versions of Fortigates and firmwares are you all running? I’m on 6.4.0 and do not get the second prompt window. Of course, I also don’t have userstore selected so that one difference.

I have FG’s with 6.2.3 , 6.2.5 , 6.4.2
They all working fine with SSL VPN authenticating against privacyidea

Additional conditions are just group selection.
I haven’t modified rlm_perl.ini files

NAS IP is the client IP adress.
IP/name is the IP of the freeradius server.