FreeRadius can't set custom variable - freeradius

We want to setup StrongSwan VPN with FreeRadius for authentication. In addition to that we want to assign different subnets to users based on AD-Groups. StrongSwan uses the class attribute in a access-accept reply for that (https://wiki.strongswan.org/projects/strongswan/wiki/EapRadius).
To my knowledge it is possible to use custom attributes in FreeRadius to store data used during the reply/proxy/control… process and send that back to StrongSwan.
Unfortunately this is not working in our FreeRadius environment and the custom attribute stays empty. It is however possible to access attributes already existing in the reply list.
This configuration for example sends back an empty Variable Reply-Message.
/etc/raddb/dictionary:
ATTRIBUTE test 3000 string
/etc/raddb/users
DEFAULT test = “TESTTEST”
/etc/raddb/sites-enabled/default
…
post-auth {
…
update reply {
Reply-Message := "%{control:test}"
}
…
}
Log-Output:
(11) [exec] = noop
(11) policy remove_reply_message_if_eap {
(11) if (&reply:EAP-Message && &reply:Reply-Message) {
(11) if (&reply:EAP-Message && &reply:Reply-Message) -> FALSE
(11) else {
(11) [noop] = noop
(11) } # else = noop
(11) } # policy remove_reply_message_if_eap = noop
(11) update reply {
(11) EXPAND %{control:test}
(11) -->
(11) Reply-Message :=
(11) } # update reply = noop
(11) } # post-auth = noop
(11) Sent Access-Accept Id 5 from 127.0.0.1:1812 to 127.0.0.1:50913 length 0
(11) MS-MPPE-Recv-Key = 0xd23e4723df9ff904741b91827518aaa48dcbca27204024965d37fdb6bece0270
(11) MS-MPPE-Send-Key = 0x4e7de0fc944a5114ab435df43fa943901870741a86571e3ccddef11b82e406e1
(11) EAP-Message = 0x03050004
(11) Message-Authenticator = 0x00000000000000000000000000000000
(11) User-Name = "raduser"
(11) Reply-Message := ""
(11) Finished request
FreeRADIUS Version 3.0.19
According to this guides, the configuration above should work:
returning custom user attributes in the radius reply
https://serverfault.com/questions/939980/freeradius-return-user-groups-in-class-field
Is there anything we’re missing? Thanks in advance.

Your reply message should be formatted as
Reply-Message := "Hello, %{User-Name}"
In your configuration file, you defined DEFAULT test = “TESTTEST” but in reply message you have mentioned "%{control:test}".
please try with it.

Related

ActiveMQ Artemis / Influx Telegraf MQTT Listener - all messages (100K) delivered, but 4K messages remain in queue

I have conducted a test sending 100K persistent MQTT messages (QoS 2) to ActiveMQ Artemis. The topic has two Telegraf listeners, one on VM 85 and the other on VM 86. These listeners write data to the InfluxDB on their respective servers.
The main goal of the test is to ensure all messages delivered to VM 85 are also delivered to VM 86 even if VM 86 is down. Before executing the test both listeners connect to the broker each with a unique client ID and with clean-session = false and subscribe to the topic using QoS 2. This ensures the subscription for each is present when the messages are sent whether or not the listeners are actually active. Neither listener is connected when the test starts. The order of operations is:
Start listener on VM 85.
Send data.
Ensure messages are delivered to listener on VM 85.
Start listener on VM 86.
Ensure messages are delivered to listener on VM 86.
The good news is that all messages are delivered to the Influx DB on both VMs. However, the relevant queue for VM 86 still shows about 4.3 K messages remaining, as shown below:
If I then restart the listener on VM 86, it shows it's writing more data, as shown below:
However, the total messages in the InfluxDB correctly remains at 100K. If InfluxDB receives a duplicate record, it will overwrite it. However, the client is incrementing by one and setting the date at each increment, so this shouldn't occur, at least from the client.
I'm not clear on why this would be. Why does the the listener on VM 86 need to be restarted to completely empty the queue?
There is one parameter I haven't tried in the Telegraf plugin:
## Maximum messages to read from the broker that have not been written by an
## output. For best throughput set based on the number of metrics within
## each message and the size of the output's metric_batch_size.
##
## For example, if each message from the queue contains 10 metrics and the
## output metric_batch_size is 1000, setting this to 100 will ensure that a
## full batch is collected and the write is triggered immediately without
## waiting until the next flush_interval.
# max_undelivered_messages = 1000
It seems the batch size defaults to 1000, based on the output messages. But the maximum messages to read before output seems to be something greater, since 4.3K are output when restarted. Except that they have already been output. That's the confusing part.
Client Code:
package abc;
import java.time.Instant;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import com.influxdb.client.domain.WritePrecision;
import com.influxdb.client.write.Point;
public class MqttPublishSample {
public static void main(String[] args) throws MqttSecurityException, MqttException, InterruptedException {
String broker = "tcp://localhost:1883";
String clientId = "JavaSample";
MemoryPersistence persistence = new MemoryPersistence();
int qos = 2;
int start = Integer.parseInt(args[0]);
int end = Integer.parseInt(args[1]);
String topic = args[2];
if (topic == null) {
topic = "testtopic/999";
}
System.out.println("start: " + start + ", end: " + end + ", topic: " + topic + " qos: " + qos);
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(false);
connOpts.setUserName("admin");
connOpts.setPassword("xxxxxxx".toCharArray());
System.out.println("Connecting to broker: " + broker);
sampleClient.connect(connOpts);
System.out.println("Connected");
for (int i = start; i <= end; i++) {
// print out every 1000
if (i%100 == 0) {
System.out.println("i: " + i);
}
try {
Point point = Point.measurement("temperature").addTag("machine", "unit43").addField("external", i)
.time(Instant.now(), WritePrecision.NS);
content = point.toLineProtocol();
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
Thread.sleep(10);
} catch (MqttException me) {
System.out.println("reason " + me.getReasonCode());
System.out.println("msg " + me.getMessage());
System.out.println("loc " + me.getLocalizedMessage());
System.out.println("cause " + me.getCause());
System.out.println("excep " + me);
me.printStackTrace();
}
}
sampleClient.disconnect();
System.out.println("Disconnected");
}
}
Telegraph Plugin on 85:
###############################################################################
# INPUT PLUGINS #
###############################################################################
[[inputs.mqtt_consumer]]
servers = ["tcp://127.0.0.1:1883"]
## Topics that will be subscribed to.
topics = [
"testtopic/#",
]
## The message topic will be stored in a tag specified by this value. If set
## to the empty string no topic tag will be created.
# topic_tag = "topic"
## When using a QoS of 1 or 2, you should enable persistent_session to allow
## resuming unacknowledged messages.
qos = 2
persistent_session = true
## If unset, a random client ID will be generated.
client_id = "InfluxData_on_86_listen_local"
## Username and password to connect MQTT server.
username = "admin"
password = "xxxxxx"
data_format = "influx"
[[inputs.mqtt_consumer]]
servers = ["tcp://10.102.11.86:1883"]
## Topics that will be subscribed to.
topics = [
"testtopic/#",
]
## The message topic will be stored in a tag specified by this value. If set
## to the empty string no topic tag will be created.
# topic_tag = "topic"
## When using a QoS of 1 or 2, you should enable persistent_session to allow
## resuming unacknowledged messages.
qos = 2
persistent_session = true
## If unset, a random client ID will be generated.
client_id = "InfluxData_on_86_listen_85"
## Username and password to connect MQTT server.
username = "admin"
password = "xxxx"
data_format = "influx"
###############################################################################
# OUTPUT PLUGINS #
###############################################################################
[[outputs.influxdb_v2]]
## The URLs of the InfluxDB cluster nodes.
##
## Multiple URLs can be specified for a single cluster, only ONE of the
## urls will be written to each interval.
urls = ["http://127.0.0.1:8086"]
## Token for authentication.
token = "xxxx"
## Organization is the name of the organization you wish to write to.
organization = "xxxx"
# ## Destination bucket to write into.
bucket = "events"
I wasn't able to replicate this issue even initially at lower volumes, although I had it twice at 100K messages.
When i added the following parameters to the Telegraf Listener:
max_undelivered_messages = 100
It seemed to slow things down, as batches were limited to 100 according to the telegraph output.
However, when I removed it, it seemed batches where still limited to 100.
Finally, I changed the same parameter to 1000:
max_undelivered_messages = 1000
After this, message batch sizes improved to well beyond 100, as they were initially.
Furthermore, at least on the third try of 100K messages, there are no longer any messages remaining in the queue after the sequence described in the question is completed.
I'm not really sure if this change did anything, but in any case the correct amount of messages were always being received.
So, I'm marking this as answered.

Doing 2FA via Freeradius with our own 2FA app

Some DATA firts:
Freeradius v3.0.17
Active Directory as LDAP
OTP app developed by ourself
What We want to achieve is 2FA via Freeradius. We are using authentication with ntlm_auth against an MS AD and on the other hand We have our own OTP script (This is working in another solution).
At first we have a policy that splits the USER and Token, like this --> username:OTP. This is working.
This procces is called at the top of authorize section on Default site
on policy.d/pol_usernamemultiotp.authorize:
pol_usernamemultiotp.authorize {
if ( &User-Name =~ /^(.*):([0-9]{6})$/) {
update request {
Stripped-User-Name := "%{1}"
User-OTP := "%{2}"
}
}
}
The ntlm_auth is working properly.
When we add the next code in authorize section on Default, the authentication jumps to Auth-Type := LDAP and wont do throught ntlm_auth.
update control {
Auth-Type := `/bin/bash /etc/freeradius/3.0/otpIB.sh '%{Stripped-User-Name}' '%{User-OTP}' '%{Client-IP-Address}'`
}
(this script returns "Accept" or "Reject" depending if the OTP is correct.)
We also try to put this update control on Post-Auth section on Default. BUT, here is the problem. Let us show you with de Freeradius -X logs
(0) mschap: Program returned code (0) and output 'NT_KEY: C1964544A5B93877F0D3FE7D9E5791D0'
(0) mschap: Adding MS-CHAPv2 MPPE keys
(0) [mschap] = ok
(0) } # authenticate = ok
(0) # Executing section post-auth from file /etc/freeradius/3.0/sites-enabled/default
(0) post-auth {
(0) update control {
(0) Executing: /bin/bash /etc/freeradius/3.0/otpIB.sh '%{Stripped-User-Name}' '%{User-OTP}' '%{Client-IP-Address}':
(0) EXPAND %{Stripped-User-Name}
(0) --> fdelfranco
(0) EXPAND %{User-OTP}
(0) --> 770355
(0) EXPAND %{Client-IP-Address}
(0) --> 10.40.9.3
(0) Program returned code (0) and output 'Reject'
(0) Auth-Type := Reject
(0) } # update control = noop
(0) update {
(0) No attributes updated
(0) } # update = noop
(0) policy remove_reply_message_if_eap {
(0) if (&reply:EAP-Message && &reply:Reply-Message) {
(0) if (&reply:EAP-Message && &reply:Reply-Message) -> FALSE
(0) else {
(0) [noop] = noop
(0) } # else = noop
(0) } # policy remove_reply_message_if_eap = noop
(0) } # post-auth = noop
(0) Sent Access-Accept Id 195 from 10.40.9.99:1812 to 10.40.9.3:21481 length 0
(0) MS-CHAP2-Success 0xf9533d36433832463034413330323043344533314246333736383533364234324641453142383843383145
(0) MS-MPPE-Recv-Key = 0x66e467b713b84475fa5ed19d93207ef3
(0) MS-MPPE-Send-Key = 0x75f6cbee712186fe6ebeca98ea9ab063
(0) MS-MPPE-Encryption-Policy = Encryption-Allowed
(0) MS-MPPE-Encryption-Types = RC4-40or128-bit-Allowed
(0) Finished request
NTLM_AUTH works perfectly and gives and Access-Accept, ignoring completely the script and the Auth-Type := Reject that returns!
Why is the Radius ignoring the state of "reject" from the script and authorizinging the user ??
Some suggestions?
Edit:
Today We managed to get this thing working without a challenge, but working. We create like some kind of new Auth Type, and we put the policy there so, When we make the Authorize parte, it calls this pseudo Auth Type in the Authenticate section of the Defaul file and then, after thar it make a call for our own policy, where We have pointed our own shell script that makes the one-time-password validation properly.
It works great with Cisco VPN client, Forti Client and with Mac OS native client for IPSEC.
Auth-Type must to be set on reply, not control.

returning custom user attributes in the radius reply

I am using (and enjoying) Freeradius v3 and I have been beating my head against something I am sure the community has already figured out.
I have a custom user attribute defined in the dictionary and included in my authorize file:
me Mygroup :="usergroup", Cleartext-Password := "password1234"
...and I am able to update the reply from the radius server by adding the following to the default site (/etc/freeradius/3.0/sites-available/default)
update reply {
Reply-Message := "additional info"
}
Running a simple radtest from the command line:
radtest me password1234 192.168.x.x 0 $secret
...gives me the following:
Sent Access-Request Id 204 from 0.0.0.0:38090 to 192.168.2.161:1812 length 77
User-Name = "me"
User-Password = "password1234"
NAS-IP-Address = 192.168.x.x
NAS-Port = 0
Message-Authenticator = 0x00
Cleartext-Password = "password1234"
Received Access-Accept Id 204 from 192.168.x.x:1812 to 0.0.0.0:0 length 53
Reply-Message = "additional info"
What variable, command line switch or other should I include to get the "Mygroup" information in the "additional info" section?
I am not trying to boil an ocean, I know there are some pretty involved group/huntgroup/permission configurations for freeradius but all I need is that data in the Reply-Message.
Thanks!
If you take a look at this question about how the users file works, you'll see that attributes with that operator, on the first line of a users file entry, get inserted into the control list.
If you want to access that attribute somewhere else, you need to add list qualifier i.e. control:Mygroup.
As you're wanting to insert the value into a string, you need to use the string interpolation syntax (referred to as xlat or string expansions in the FreeRADIUS docs). For simple attribute expansions, you just wrap the attribute name and its qualifiers in %{ and }.
So your final unlang update block would look something like:
update reply {
Reply-Message := "%{control:Mygroup}"
}

FreeRadius rlm_ldap::ldap_groupcmp: ldap_get_values() failed

I'm in the process of configuring freeRadius to our ldap server. I can authenticate from user perspective to radius client. But when radius is trying query about the to ldap groups we are getting these below error
[ldap] performing search in uid=vchevakula#test.us,ou=users,dc=test,dc=us, with filter (objectclass=*)
rlm_ldap::ldap_groupcmp: ldap_get_values() failed or if we are changing any in group membership filter we are getting implementation error
[ldap] ldap_release_conn: Release Id: 0
[files] expand: (&(objectClass=GroupOfUniqueNames)(UniqueMember=%{User-Name})) -> (&(objectClass=GroupOfUniqueNames)(UniqueMember=vchevakula#test.us))
[ldap] ldap_get_conn: Checking Id: 0
[ldap] ldap_get_conn: Got Id: 0
[ldap] performing search in dc=test,dc=us, with filter (&(cn=Dev-Nw)(&(objectClass=GroupOfUniqueNames)(UniqueMember=vchevakula#cstest.us)))
[ldap] object not found
[ldap] ldap_release_conn: Release Id: 0
[ldap] ldap_get_conn: Checking Id: 0
[ldap] ldap_get_conn: Got Id: 0
[ldap] performing search in
uid=vchevakula#cstest.us,ou=users,dc=test,dc=us, with filter (objectclass=*)
rlm_ldap::ldap_groupcmp: ldap_get_values() failed
[ldap] ldap_release_conn: Release Id: 0
users file in free radius
DEFAULT Ldap-Group == "Dev-Nw"
DEFAULT Ldap-Group == "SRE"
Reply-Message = "You are allowed"
modules/ldap in free radius
groupname_attribute = cn
groupmembership_filter = "(&(objectClass=GroupOfUniqueNames)(UniqueMember=%{User-Name}))"
groupmembership_attribute = radiusGroupName
I tried changing the groupmembership filter but none of them worked until right now. I'm getting the same error that it couldn't figure out . Freeradius -X keeps failing on the finding groups
groupname_attribute = cn
#groupmembership_filter = "(&(objectClass=GroupOfUniqueNames)(uniquemember=%{control:Ldap-UserDn}))"
#groupmembership_filter = "(|(&(objectClass=GroupOfNames)(member=%{control:Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{control:Ldap-UserDn})))"
#groupmembership_filter = "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"
groupmembership_filter = "(&(objectClass=GroupOfUniqueNames)(UniqueMember=%{User-Name}))"
groupmembership_attribute = radiusGroupName
ldap attributes from ldap server
dn: cn=SRE,ou=groups,dc=test,dc=us
objectClass: top
objectClass: groupofUniqueNames
cn: SRE
uniqueIdentifier: XXXXXXX
description: SRE Team
uniqueMember: uid=vchevakula#test.us,ou=users,dc=test,dc=us
uniqueMember: uid=nuser#test.us,ou=users,dc=test,dc=us
need some help in configuring ldap groups in freeradius
Hello I have resolved my problem
By adding this below line to my configuration in freeradius server /etc/freeradius/modules/ldap
groupmembership_filter = "(&(objectClass=GroupOfUniqueNames)(uniqueMember=%{control:Ldap-UserDn}))"

How to get User-Password in inner tunnel from iOS

I am attempting to setup a freeradius service to allow authentication against a https api. And i have it working for most android devices, even my Mac book pro works. However when we attempt to use an iOS device (iPad, iPhone), the inner tunnel fails to get the User-Password field.
so the current setup is EAP -> TTLS -> custom auth
eap.conf ttls section
ttls {
default_eap_type = md5
copy_request_to_tunnel = yes
use_tunneled_reply = yes
virtual_server = "inner-tunnel"
}
inner-tunnel custom auth
authorize {
...
update control {
Auth-Type := `/usr/local/bin/admin_portal.py %{User-Name} '%{User-Password}' %{Calling-Station-Id}`,
Fall-Through = Yes
}
}
When I run in debug mode, I get the following output
expand: %{User-Name} -> user#somedomain.com
expand: '%{User-Password}' -> ''
expand: %{Calling-Station-Id} -> 01-23-45-67-89-ab
However, when i use a non iOS device, the password is populated.
Any help would be appreciated.
Thank you.
You need a TTLS inner method that sends the password in the clear. The most common method is TTLS-PAP.
If the supplicant authenticates with TTLS-PAP, the proxied request (to the inner tunnel) will contain a User-Password attribute, with the value the user entered (or was cached) by their supplicant.
Below is an example of setting up the profile with the Apple Configurator.

Resources