Count9 #7
@@ -106,13 +106,14 @@ public class RadiusService : IRadiusService
|
|||||||
Value = password
|
Value = password
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set Session-Timeout to 60 seconds to force frequent re-authentication (validation)
|
// Set Session-Timeout to the full allowed time. When this expires, the AP will drop the user natively.
|
||||||
|
long sessionTimeoutSeconds = (long)config.DefaultSessionTimeMinutes * 60;
|
||||||
_db.RadReply.Add(new RadReply
|
_db.RadReply.Add(new RadReply
|
||||||
{
|
{
|
||||||
Username = username,
|
Username = username,
|
||||||
Attribute = "Session-Timeout",
|
Attribute = "Session-Timeout",
|
||||||
Op = "=",
|
Op = "=",
|
||||||
Value = "60"
|
Value = sessionTimeoutSeconds.ToString()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set Max-Octets (in bytes)
|
// Set Max-Octets (in bytes)
|
||||||
@@ -134,14 +135,7 @@ public class RadiusService : IRadiusService
|
|||||||
Value = "60"
|
Value = "60"
|
||||||
});
|
});
|
||||||
|
|
||||||
// Re-authenticate (instead of disconnect) when Session-Timeout fires
|
|
||||||
_db.RadReply.Add(new RadReply
|
|
||||||
{
|
|
||||||
Username = username,
|
|
||||||
Attribute = "Termination-Action",
|
|
||||||
Op = "=",
|
|
||||||
Value = "1"
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create Guest Profile record
|
// Create Guest Profile record
|
||||||
var profile = new GuestProfile
|
var profile = new GuestProfile
|
||||||
@@ -233,11 +227,11 @@ public class RadiusService : IRadiusService
|
|||||||
profile.SessionTimeMinutes = newSessionTimeMinutes;
|
profile.SessionTimeMinutes = newSessionTimeMinutes;
|
||||||
profile.DataLimitMb = newDataLimitMb;
|
profile.DataLimitMb = newDataLimitMb;
|
||||||
|
|
||||||
// Ensure Session-Timeout is strictly 60 seconds for frequent validation
|
// Update RadReply Session-Timeout to the full allowed time
|
||||||
var sessionReply = await _db.RadReply.FirstOrDefaultAsync(rr => rr.Username == profile.Username && rr.Attribute == "Session-Timeout");
|
var sessionReply = await _db.RadReply.FirstOrDefaultAsync(rr => rr.Username == profile.Username && rr.Attribute == "Session-Timeout");
|
||||||
if (sessionReply != null)
|
if (sessionReply != null)
|
||||||
{
|
{
|
||||||
sessionReply.Value = "60";
|
sessionReply.Value = (newSessionTimeMinutes * 60).ToString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -246,7 +240,7 @@ public class RadiusService : IRadiusService
|
|||||||
Username = profile.Username,
|
Username = profile.Username,
|
||||||
Attribute = "Session-Timeout",
|
Attribute = "Session-Timeout",
|
||||||
Op = "=",
|
Op = "=",
|
||||||
Value = "60"
|
Value = (newSessionTimeMinutes * 60).ToString()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +285,9 @@ public class RadiusService : IRadiusService
|
|||||||
});
|
});
|
||||||
|
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
|
|
||||||
|
// Disconnect active sessions immediately
|
||||||
|
await DisconnectActiveSessionsAsync(profile.Username);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteUserAsync(int profileId)
|
public async Task DeleteUserAsync(int profileId)
|
||||||
@@ -308,6 +305,9 @@ public class RadiusService : IRadiusService
|
|||||||
_db.GuestProfiles.Remove(profile);
|
_db.GuestProfiles.Remove(profile);
|
||||||
|
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
|
|
||||||
|
// Disconnect active sessions immediately
|
||||||
|
await DisconnectActiveSessionsAsync(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ResetUserPasswordAsync(int profileId, string newPassword)
|
public async Task ResetUserPasswordAsync(int profileId, string newPassword)
|
||||||
@@ -374,4 +374,43 @@ public class RadiusService : IRadiusService
|
|||||||
}
|
}
|
||||||
return new string(result);
|
return new string(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task DisconnectActiveSessionsAsync(string username)
|
||||||
|
{
|
||||||
|
var activeSessions = await _db.RadAcct
|
||||||
|
.Where(ra => ra.Username == username && ra.AcctStopTime == null)
|
||||||
|
.Select(ra => ra.NasIpAddress)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var radiusSecret = Environment.GetEnvironmentVariable("RADIUS_SECRET") ?? "radpass";
|
||||||
|
|
||||||
|
foreach (var nasIp in activeSessions)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(nasIp)) continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var process = new System.Diagnostics.Process
|
||||||
|
{
|
||||||
|
StartInfo = new System.Diagnostics.ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "sh",
|
||||||
|
Arguments = $"-c \"echo 'User-Name={username}' | radclient -x {nasIp}:3799 disconnect '{radiusSecret}'\"",
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
process.Start();
|
||||||
|
await process.WaitForExitAsync();
|
||||||
|
_logger.LogInformation("Sent manual RADIUS Disconnect-Request to NAS {NasIp} for user {Username}", nasIp, username);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to send manual RADIUS Disconnect-Request to NAS {NasIp}", nasIp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user