Compare commits

..

2 Commits

Author SHA1 Message Date
Alex Rennie-Lis
3a58c19c44 Added session duration handling 2024-04-09 13:26:55 +01:00
Alex Rennie-Lis
2b7fbfdebd Issue 1, untested 2024-04-09 13:18:23 +01:00
6 changed files with 105 additions and 23 deletions

View File

@ -1,11 +0,0 @@
{
"ports": {
"radius_authentication": 1812,
"radius_accounting": 1813
},
"client_secret": "password",
"storage": "json:./data.json",
"default_vlan_enabled": true,
"default_vlan_id": 90,
"mac_auth_only": true
}

View File

@ -9,11 +9,6 @@
"username": "AB:CD:EF:12:34:56",
"password": "AB:CD:EF:12:34:56",
"vlan": "123"
},
{
"username": "abcdef123456",
"password": "abcdef123456",
"vlan": "123"
}
]
}

View File

@ -30,6 +30,7 @@ catch (error) {
client_secret: "password",
default_vlan_enabled: false,
mac_auth_only: false
session_duration: 60
}
}
if (process.env['NETRADIUS_PORT_RADIUS_AUTH']) config.ports.radius_authentication = process.env['NETRADIUS_PORT_RADIUS_AUTH'];
@ -40,6 +41,7 @@ if (process.env['NETRADIUS_DEFAULT_VLAN']) config.default_vlan_enabled = process
if (process.env['NETRADIUS_DEFAULT_VLAN_ID']) config.default_vlan_id = process.env['NETRADIUS_DEFAULT_VLAN_ID'];
if (process.env['NETRADIUS_CLIENT_SECRET']) config.client_secret = process.env['NETRADIUS_CLIENT_SECRET'];
if (process.env['NETRADIUS_MAC_AUTH_ONLY']) config.mac_auth_only = process.env['NETRADIUS_MAC_AUTH_ONLY'];
if (process.env['NETRADIUS_SESSION_DURATION']) config.session_duration = process.env['NETRADIUS_SESSION_DURATION'];
// Set defaults
if (!config.ports.radius_authentication) config.ports.radius_authentication = 1812;

View File

@ -1,4 +1,5 @@
const fs = require ('fs');
const timeauth = require ('./time.js');
try {
var data = JSON.parse (fs.readFileSync ('./data.json').toString ());
@ -19,7 +20,9 @@ const persistData = () => {
content.users.push ({
username: user,
password: users[user].password,
vlan: users[user].vlan
vlan: users[user].vlan,
description: users[user].description,
rules: users[user].rules
});
});
fs.writeFileSync ('./data.json', JSON.stringify (content, null, 2));
@ -29,7 +32,9 @@ users = {};
data.users.forEach ((e) => {
users[e.username] = {
password: e.password,
vlan: e.vlan
vlan: e.vlan,
description: e.description,
rules: e.rules
}
});
@ -40,9 +45,16 @@ module.exports = {
password = password.toLowerCase ().replace (/[:-]/g, '');
}
if (users[username] && users[username].password == password) {
return {
vlan: users[username].vlan
};
// Check time
var rules = users[username].rules || [];
if (timeauth.checkAuth (rules)) {
return {
vlan: users[username].vlan
};
}
else {
return false;
}
}
else {
return false;
@ -59,11 +71,13 @@ module.exports = {
password = password.toLowerCase ().replace (/[:-]/g, '');
}
var description = payload.description || "";
var rules = payload.rules || [];
var vlan = payload.vlan;
users[username] = {
password: password,
vlan: vlan,
description: description
description: description,
rules: rules
};
persistData ();
callback ("OK\n\n", null);

View File

@ -18,6 +18,7 @@ module.exports = {
}
var user = data.authUser (username, password);
var vlan = false;
var code = 'Access-Reject';
if (user) {
log.write (username + " access granted to VLAN " + user.vlan);
code = 'Access-Accept';
@ -42,7 +43,8 @@ module.exports = {
attributes: {
"Tunnel-Medium-Type": 6,
"Tunnel-Type": 13,
"Tunnel-Private-Group-Id": vlan
"Tunnel-Private-Group-Id": vlan,
"Session-Timeout": config.radius.session_duration || 60
}
});
callback (response, null);

80
code/lib/time.js Normal file
View File

@ -0,0 +1,80 @@
const rangeStringToArray = (str) => {
// Split the string by hyphen
const parts = str.split ("-");
// Validate input format (two numbers separated by hyphen)
if (parts.length !== 2 || isNaN (parts[0]) || isNaN (parts[1])) {
return null; // Return null for invalid format
}
// Convert strings to numbers
const start = parseInt (parts[0], 10);
const end = parseInt (parts[1], 10);
// Check if start is less than or equal to end (inclusive range)
if (start > end) {
return null; // Return null for invalid range
}
// Use Array.from() to create an array with sequence
return Array.from ({ length: end - start + 1 }, (_, i) => start + i);
};
const resolveRange = (str) => {
const numberSets = str.split (","); // Split by commas
const numbers = [];
for (const set of numberSets) {
// Check if it's a range
if (set.includes ("-")) {
const range = rangeStringToArray (set); // Use the previous function
if (range) {
numbers.push(...range); // Spread operator to add elements from range array
}
else {
const num = parseInt(set, 10);
// Check if conversion is successful (valid number)
if (!isNaN(num)) {
numbers.push(num);
}
}
}
}
return numbers;
}
module.exports = {
checkAuth: (rules = []) => {
var authorised = false;
if (rules.length > 0) {
var now = new Date ();
var minuteOfDay = (now.getHours () * 60) + now.getMinutes (); // 0 - 1439
var day = now.getDay (); // 1 - 7
var date = now.getDate (); // 1 - 31
var month = now.getMonth () + 1; // 1 - 12
var actions = [];
rules.forEach ((rule) => {
var valid = false;
// Process rule
var r = {
startMinute: parseInt (rule.startTime.split (":")[0] * 60) + parseInt (rule.startTime.split (":")[1]),
endMinute: parseInt (rule.endTime.split (":")[0] * 60) + parseInt (rule.endTime.split (":")[1]),
days: resolveRange (rule.weekdays),
dates: resolveRange (rule.dates),
months: resolveRange (rule.months)
}
if (
minuteOfDay >= r.startMinute &&
minuteOfDay <= r.endMinute &&
r.days.indexOf (day) !== -1 &&
r.dates.indexOf (date) !== -1 &&
r.months.indexOf (month) !== -1
) {
actions.push (rule.action.toLowerCase ());
}
});
if (actions.indexOf ("allow")) {
authorised = true;
}
if (actions.indexOf ("deny")) {
authorised = false;
}
}
return authorised;
}
}