FortiGate SSL-VPN using windows AD groups with Privacyidea

I want to use Active Directory users for authentication and it worked with me but I couldn’t configure the authentication to be work per Active Directory Group

Now all Active Directory Groups can connect to FortiGate using ssl-vpn but I want to specify only some groups to be authenticated groups

rule all users can connect, and it work with no errors

but when try to configure policy to specific domain group it didn’t work and it gives me the permission is denied

Privacyidea Configuration

Path=== /etc/privacyidea/rlm_perl.ini

[Attribute Filter-Id]

dir = user

userAttribute = group

regex = CN=Test-otp, OU=VPN-Users,DC=AD,DC=com

ldap configs

Freeradius Logs

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Config File /etc/privacyidea/rlm_perl.ini found!

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Debugging config:

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Default URL ttps://localhost/validate/check

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Looking for config for auth-type Perl

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Setting client IP to 10.10.10.10.

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Auth-Type: Perl

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: url: https://localhost/validate/check

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: user sent to privacyidea: otp2

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: realm sent to privacyidea:

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: resolver sent to privacyidea:

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: client sent to privacyidea: 10.10.10.10

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: state sent to privacyidea: 5642131642123132

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: urlparam pass

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: urlparam state

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: urlparam client

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: urlparam user

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Request timeout: 10

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: Not verifying SSL certificate!

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: elapsed time for privacyidea call: 0.132376

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: privacyIDEA access granted

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: ++++ Parsing group: Attribute

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: +++++ Found member ‘Attribute Filter-Id’

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: ++++++ Attribute: IF ‘user’->‘group’ == CN=Test-otp, OU=VPN-Users,DC=AD,DC=com’ THEN ‘Filter-Id’

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: ++++++ searching in directory user

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: +++++++ User attribute is a list: ARRAY(ZxYYYYYY)

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: +++++++ trying to match CN=Test-otp, OU=VPN-Users,DC=AD,DC=com

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: ++++++++ Result: Add RADIUS attribute Filter-Id =

Tue Nov 30 14:46:36 2021 : Info: rlm_perl: return RLM_MODULE_OK

privacyidea log

[2021-11-30 14:46:36,267][2161][140709409437440][INFO][privacyidea.lib.resolvers.LDAPIdResolver:322] Setting system wide POOLING_LOOP_TIMEOUT to 10.

[2021-11-30 14:46:36,268][2161][140709409437440][INFO][privacyidea.lib.user:237] user ‘otp2’ found in resolver ‘AD.com

[2021-11-30 14:46:36,268][2161][140709409437440][INFO][privacyidea.lib.user:238] userid resolved to ‘XXXXXXXX-YYYY-ZZZZ-XXXX-YYYYYYYYYYYY’

[2021-11-30 14:46:36,337][2161][140709409437440][INFO][privacyidea.api.lib.postpolicy:471] There is no machine with IP=IPAddress(‘127.0.0.1’)

Use a radius test client like on the privacyIDEA machine to test the radius responses.

On the linux machine you can do

echo "User-Name=test-otp, User-Password=secret123456" | radclient -x -s localhost auth testing123

You will see the attributes in the RADIUS response an it will be a bit easier for you to debug.

Which version of the freeradius-plugin are you using?

FreeRADIUS Version 3.0.16

that is replay from radius test

Received Access-Accept Id 61 from 127.0.0.1:1812 to 0.0.0.0:0 length 48
Reply-Message = “privacyIDEA access granted”
Packet summary:
Accepted : 1
Rejected : 0
Lost : 0
Passed filter : 1
Failed filter : 0

when i do privacyidea test

http --verify no POST https://localhost/validate/check user=otp-test pass=secret123456

HTTP/1.1 200 OK
Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 1188
Content-Type: application/json
Date: Mon, 06 Dec 2021 08:59:26 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.29 (Ubuntu)

{
“detail”: {
“message”: “matching 1 tokens”,
“otplen”: 6,
“serial”: “TOTP5468F04”,
“threadid”: 140526974829088,
“type”: “totp”,
“user”: {
“email”: “”,
“givenname”: “otp-test”,
“group”: [
“CN=VPN-Group1,OU=Users,DC=AD,DC=com”,

        ],
        "mobile": "",
        "password": "",
        "phone": "",
        "surname": "",
        "username": "otp-test"
    }
},

Have you setup an attribute filter in rlm_perl.ini?
https://privacyidea.readthedocs.io/en/latest/application_plugins/rlm_perl.html#mapping-privacyidea-return-values-to-radius-attribute-value-pairs

Based on what you posted, it would look like

[Attribute Fortinet-Group-Name]
dir = user
userAttribute = memberOf
regex = CN=(.*?),.*

The regex line at the end is regular expression. The value in the paranthesis is a capture group and is what will be sent in the RADIUS response. The full regex says match CN= and discard, then grab anything else that comes after that, lazily* and put it in a capture group until you hit a comma and then match on anything.

*lazy matching when used with a wildcard, like above, tells regular expression to match as few characters as possible. In the above example, if the question mark wasn’t there to indicate lazy matching, it would capture and return everything after CN=.

1 Like

Also, have you setup a policy that sends user details in the response?
https://privacyidea.readthedocs.io/en/latest/policies/authorization.html#add-user-in-response

I would recommend you restrict this policy by client ip so that these user details are only sent to authorized devices.

hi
thank you very much it is work with me
i have question how can i add multiple groups ?

The way the regex is setup in the example I provided above, it will send all groups the user is a member of to the Fortigate. However, I in my testing this was a problem as the Fortigate only processes the last value it receives for this field. So if RADIUS returns groupA, groupB, groupC in the Fortinet-Group-Name, it will only process and see groupC as it was the last one it received in the RADIUS response. To get around this limitation, you’ll need to specify the group name in the regular expression.

CN=(groupA),.*

This will ensure that only groupA is captured and sent to the Fortigate. If you want to send multiple groups, you need to use a pipe, which regular expression interprets as OR

CN=(groupA|groupB),.*

However, this still requires that you practice strict group membership management in your user directory. If a user is a member of groupA and groupB, you’ll encounter problems.

In Fortigate, you’ll just setup firewall groups and reference your PrivacyIDEA radius server and specify a group, which should match the group name that RADIUS will send to the Fortigate.

2 Likes

hi walker
thank you so much

1 Like