Sommaire
Introduction
Le but ici, est de générer un fichier plat pour Freeradius afin de réaliser une authentification par adresse MAC, celles-ci étant contenu dans une table MySQL.
Pour réaliser ceci, nous allons utiliser :
- une base de données MySQL
- le framework .Net Core 2.2
Vous pouvez récupérer le code source ici : https://gitlab.com/Flo0r/freeradius-mysql-generator
Pré-requis
Installation du SDK .Net Core 2.2
Il faut tout d’abord télécharger le SDK .Net Core 2.2, que vous trouverez ici : https://dotnet.microsoft.com/download/dotnet-core/sdk-for-vs-code
Construction de la base de données
Pour notre projet, nous utiliserons une base de données MySQL.
Création de la base de données
Tout d’abord, il faut créer la base de données, comme ceci :
CREATE DATABASE radiusManager COLLATE 'utf8_general_ci';
Création d’un utilisateur de connexion
CREATE USER 'DataIntegrator'@'localhost' IDENTIFIED BY 'MyPasswordNeedToBeSecure';
GRANT SELECT ON *.* TO 'DataIntegrator'@'localhost';
FLUSH PRIVILEGES;
Notre utilisateur, dans ce cas, n’a besoin que de réaliser des opérations de lecture.
Création de la table d’autorisation des adresses MACs
Une fois notre base de données créée, nous allons nous concentrer sur la création de notre table contenant la correspondance entre nos utilisateurs et nos adresses MACs
CREATE TABLE `wifi_radius` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`macAddress` CHAR(17) NOT NULL,
`vlan` SMALLINT(6) NOT NULL,
`name` VARCHAR(50) NOT NULL,
`firstName` VARCHAR(50) NOT NULL,
`mail` VARCHAR(150) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
Création d’utilisateurs
Désormais, il ne nous reste plus qu’à insérer nos utilisateurs dans notre base de données
INSERT INTO `wifi_radius` (`macAddress`, `vlan`, `name`, `firstName`, `mail`) VALUES ('00:56:00:01:02:03', 100, 'John', 'Doe', 'john.doe@null.net');
INSERT INTO `wifi_radius` (`macAddress`, `vlan`, `name`, `firstName`, `mail`) VALUES ('00:56:00:04:05:06', 200, 'Bob', 'Dylan', 'bob.dylan@null.net');
A ce moment, notre base de données est prête.
Construction de notre projet
Pour créer notre application, nous utilisons l’IDE Visual Studio Code avec le Terminal PowerShell intégré.
L’ensemble des commandes dotnet utilise ce Terminal.
Démarrage d’un projet .Net Core
Pour démarrer notre nouveau projet, nous allons réaliser une application Console, comme ceci :
dotnet new console
Si nous regardons un peu les fichiers générés, nous avons un fichier .csproj, qui contient ceci :
Installation des dépendances
Pour que notre application fonctionne, nous utilisons un package qui nous permet d’utiliser MySQL (https://www.nuget.org/packages/MySql.Data/) :
dotnet add package MySql.Data --version 8.0.17
Création d’une classe MySQL
Afin de gérer notre connexion à notre base de données ainsi que de récupérer nos données, nous allons créer une classe MySQL qui aura pour but de fournir une couche d’abstraction de la base de données.
En effet en créant une classe MySQL avec certains verbes génériques, ce sera plus facile de changer de type de base de données en créant une classe similaire avec les mêmes verbes.
using System;
using System.Data;
using MySql.Data.MySqlClient;
namespace Freeradius.GenerateUsersFileFromMySQL
{
public class MYSQL
{
private string s_ConnexionString;
private IDbConnection v_DbConnexion;
private IDbCommand v_DbCommand;
private string sqlRequest;
private bool canStart = false;
/**
Ouvre une connexion vers la base de données
*/
public MYSQL (string aConnexionString)
{
try {
this.s_ConnexionString = aConnexionString;
this.v_DbConnexion = new MySqlConnection(aConnexionString);
this.v_DbConnexion.Open();
canStart = true;
} catch (MySqlException) {
System.Console.WriteLine ("Can't connect to DB !");
}
}
/**
Execute une requête et récupère les données
*/
public void ExecuteRequest(ref IDataReader p_Reader)
{
if(!canStart)
return;
try {
this.v_DbCommand = this.v_DbConnexion.CreateCommand ();
this.v_DbCommand.CommandText = this.sqlRequest;
p_Reader = this.v_DbCommand.ExecuteReader ();
} catch (MySqlException p_Error) {
Console.WriteLine (p_Error.ToString());
return;
}
}
/**
Permet d'initialiser la requête SQL
*/
public void setRequest(string anSqlRequest) {
this.sqlRequest = anSqlRequest;
}
~MYSQL() {
this.v_DbCommand.Dispose();
this.v_DbCommand = null;
this.v_DbConnexion.Close();
this.v_DbConnexion = null;
}
}
}
Une fois que l’on est capable d’intérroger notre base de données, il faut transformer nos données en fichier plat.
Création d’une classe DataIntegrator
Cette classe permet de récupérer des données d’une interface IDataReader en provenance d’une base de données ainsi que de les transformer au format Freeradius.
Elle a une structure assez classique en objet avec un Constructeur et un ensemble de méthode permettant de faire le travail demandé.
Le constructeur a 4 arguments, le premier est cette interface qui est passée par référence.
Les deux derniers arguments servent à gérer le format de l’adresse MAC de sortie, en effet selon les constructeurs, il y a plusieurs formats d’écriture des bornes.
using System;
using System.IO;
using System.Data;
namespace Freeradius.GenerateUsersFileFromMySQL
{
public class DataIntegrator
{
String sPath = "";
Char cMacSeparator;
Char cMacSeparatorToReplace;
IDataReader v_Reader = null;
/**
Constructeur du DataIntegrator
p_Reader = référence vers l'interface de flux de données
p_Path = Path vers le fichier à enregistrer
p_MacSeparator & p_MacSeparatorToReplace = Séparateurs à remplacer selon le format attendu de l'adresse MAC
*/
public DataIntegrator(ref IDataReader p_Reader, String p_Path, Char p_MacSeparator, Char p_MacSeparatorToReplace = ':') {
sPath = p_Path;
cMacSeparator = p_MacSeparator;
cMacSeparatorToReplace = p_MacSeparatorToReplace;
v_Reader = p_Reader;
}
/**
Permet de transformer des données sur la base d'un IDataReader et de les enregistrer dans un fichier selon le format Freeradius
*/
public void Transform() {
if(null == v_Reader) {
return;
}
string generatedString = "";
File.Delete (sPath);
while (v_Reader.Read()) {
if("" != generatedString) generatedString += "\n\n";
generatedString += v_Reader[0].ToString().Replace(cMacSeparator, cMacSeparatorToReplace) + " Auth-Type := EAP\n" +
" Tunnel-type = VLAN,\n" +
" Tunnel-Medium-Type = 802,\n" +
" Tunnel-Private-Group-ID = " + v_Reader[1].ToString();
}
// Inscription des données dans le fichier plat
if (!File.Exists (sPath)) {
File.WriteAllText (@sPath, generatedString);
} else {
File.AppendAllText (@sPath, generatedString);
}
// Une fois que l'on a autorisé les adresses MACs, les autres doivent être rejetée.
if (File.Exists (sPath)) {
File.AppendAllText (@sPath, "\n\nDEFAULT Auth-Type := Reject\n"
+ " Reply-Message = \"Access rejected.\"");
}
Console.WriteLine ("Success file generation !");
}
/**
Fermeture de l'itérateur
*/
public void Close () {
if(null != v_Reader) {
v_Reader.Close();
}
}
}
}
Et pour finir nous devons construire notre application avec les différentes instanciations.
Création de notre programme
Ici nous allons d’abord récupérer nos données provenant de notre base puis nous allons les traiter et les insérer dans un fichier plat.
using System.Data;
namespace Freeradius.GenerateUsersFileFromMySQL
{
class MainClass
{
public static void Main (string[] args)
{
// Récupération des données de la base MySQL
MYSQL myConnexion = new MYSQL("Server=localhost;Database=radiusManager;User ID=DataIntegrator;Password=MyBestPassword;");
myConnexion.setRequest ("SELECT macAddress, vlan FROM `wifi_radius`;");
IDataReader result = null;
myConnexion.ExecuteRequest(ref result);
// Transformation des données en fichier plat
DataIntegrator integrate = new DataIntegrator(ref result, "/etc/freeradius/users", ':');
integrate.Transform();
integrate.Close();
}
}
}
Construction & exécution du programme
Nous pouvons construire notre programme afin de vérifier qu’il n’y a pas d’errreur :
dotnet build
Exécution de notre programme via la commande dotnet run :
dotnet run
Publication du programme
Une fois notre programme validé, il existe différents modes de déploiement d’une application .Net Core.
Ceux-ci sont listés ici : https://docs.microsoft.com/fr-fr/dotnet/core/deploying/deploy-with-cli
Nous ne verrons qu’un seul type, le déploiement de package autonome.
Déploiement du package autonome
Si nous regardons comment réaliser un package autonome nous avons cette syntaxe :
dotnet publish -c Release -r <RID> --self-contained true
Le RID correspond à la plateforme sur laquelle nous voulons déployer.
Nous pouvons trouver les différentes RIDs correspondant aux différentes plateformes ici : https://docs.microsoft.com/fr-fr/dotnet/core/rid-catalog
- Pour réaliser une publication pour un environnement de production Microsoft :
dotnet publish -c Release -r win-x64 --self-contained true
- Pour réaliser une publication pour un environnement de production Linux :
dotnet publish -c Release -r linux-x64 --self-contained true
Si nous regardons notre projet, nous voyons ceci dans le dossier bin\Release :
Nous voyons que pour chacune des plateformes, les binaires ont été générés avec l’ensemble des dépendances que nous avons utilisés.
Une fois publié, nous pouvons executer, en fonction de notre plateforme, notre executable, comme ceci :