package main import ( "crypto/sha256" "crypto/rand" "math/big" "database/sql" "encoding/hex" "log" // "strconv" "net/http" "github.com/gin-gonic/gin" _ "github.com/mattn/go-sqlite3" ) type User struct { ID int Name string UIDNumber int PrimaryGroup int OtherGroups string GivenName string SN string Mail string LoginShell string HomeDirectory string Disabled int PassSHA256 string OTPSecret string YubiKey string SSHKeys string CustAttr string } // Structure représentant un groupe LDAP type LDAPGroup struct { ID int `json:"id"` Name string `json:"name"` GIDNumber int `json:"gidnumber"` } func createTable(db *sql.DB) { query := ` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, uidnumber INTEGER NOT NULL, primarygroup INTEGER NOT NULL, othergroups TEXT DEFAULT '', givenname TEXT DEFAULT '', sn TEXT DEFAULT '', mail TEXT DEFAULT '', loginshell TEXT DEFAULT '', homedirectory TEXT DEFAULT '', disabled SMALLINT DEFAULT 0, passsha256 TEXT DEFAULT '', otpsecret TEXT DEFAULT '', yubikey TEXT DEFAULT '', sshkeys TEXT DEFAULT '', custattr TEXT DEFAULT '{}' ); ` _, err := db.Exec(query) if err != nil { log.Fatalf("Failed to create table: %v", err) } } func hashPassword(password string) string { hash := sha256.New() hash.Write([]byte(password)) return hex.EncodeToString(hash.Sum(nil)) } func generateRandomPassword(maxLength int) string { const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=<>?/|" password := make([]byte, maxLength) for i := range password { charIndex, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) password[i] = charset[charIndex.Int64()] } return string(password) } func generatePasswordSHA256(maxLength int) string { randomPassword := generateRandomPassword(maxLength) return hashPassword(randomPassword) } func authenticateUser(db *sql.DB, name, hashedPassword string) bool { var user User query := "SELECT * FROM users WHERE name = ? AND passsha256 = ?" err := db.QueryRow(query, name, hashedPassword).Scan( &user.ID, &user.Name, &user.UIDNumber, &user.PrimaryGroup, &user.OtherGroups, &user.GivenName, &user.SN, &user.Mail, &user.LoginShell, &user.HomeDirectory, &user.Disabled, &user.PassSHA256, &user.OTPSecret, &user.YubiKey, &user.SSHKeys, &user.CustAttr, ) return err == nil } // Fonction pour récupérer le dernier `uidnumber` dans la table `users` func getLastUIDNumber(db *sql.DB) (int, error) { // Requête SQL pour récupérer le dernier uidnumber var lastUIDNumber int err := db.QueryRow("SELECT MAX(uidnumber) FROM users").Scan(&lastUIDNumber) if err != nil { if err == sql.ErrNoRows { // Si aucune ligne n'est trouvée, retourner 0 return 0, nil } return 0, err } return lastUIDNumber, nil } func createUser(db *sql.DB, name, password string) bool { hashedPassword := hashPassword(password) query := "INSERT INTO users (name, passsha256) VALUES (?, ?)" _, err := db.Exec(query, name, hashedPassword) return err == nil } func fetchUsers(db *sql.DB) []User { query := "SELECT id, name, sn, givenname, mail FROM users" rows, err := db.Query(query) if err != nil { log.Fatalf("Failed to fetch users: %v", err) } defer rows.Close() var users []User for rows.Next() { var user User err := rows.Scan(&user.ID, &user.Name, &user.SN, &user.GivenName, &user.Mail) if err != nil { log.Fatalf("Failed to scan user: %v", err) } users = append(users, user) } return users } func fetchUserByID(db *sql.DB, id string) User { query := "SELECT * FROM users WHERE id = ?" var user User err := db.QueryRow(query, id).Scan( &user.ID, &user.Name, &user.UIDNumber, &user.PrimaryGroup, &user.OtherGroups, &user.GivenName, &user.SN, &user.Mail, &user.LoginShell, &user.HomeDirectory, &user.Disabled, &user.PassSHA256, &user.OTPSecret, &user.YubiKey, &user.SSHKeys, &user.CustAttr, ) if err != nil { log.Fatalf("Failed to fetch user: %v", err) } return user } func updateUser(db *sql.DB, id, name, givenName, sn, mail string, sshkeys string) { query := "UPDATE users SET name = ?, givenname = ?, sn = ?, mail = ?, sshkeys = ? WHERE id = ?" _, err := db.Exec(query, name, givenName, sn, mail, sshkeys, id) if err != nil { log.Fatalf("Failed to update user: %v", err) } } // Fonction pour récupérer tous les groupes LDAP func fetchLDAPGroups(db *sql.DB) ([]LDAPGroup, error) { // Préparer la requête SQL pour récupérer les groupes rows, err := db.Query("SELECT id, name, gidnumber FROM ldapgroups") if err != nil { return nil, err } defer rows.Close() // Initialiser un tableau pour stocker les groupes var groups []LDAPGroup // Parcourir les résultats de la requête for rows.Next() { var group LDAPGroup if err := rows.Scan(&group.ID, &group.Name, &group.GIDNumber); err != nil { return nil, err } // Ajouter le groupe à la liste groups = append(groups, group) } // Vérifier si des erreurs sont survenues lors du parcours des lignes if err := rows.Err(); err != nil { return nil, err } return groups, nil } func main() { // Initialize database connection db, err := sql.Open("sqlite3", "./users.db") if err != nil { log.Fatal(err) } defer db.Close() // Create table if it doesn't exist createTable(db) // Initialize Gin router router := gin.Default() // Serve HTML templates router.LoadHTMLGlob("templates/*") // Middleware for session authentication router.Use(func(c *gin.Context) { // Skip authentication check for login page if c.Request.URL.Path == "/" || c.Request.URL.Path == "/login" { c.Next() return } // Check if user is authenticated session, err := c.Cookie("session") if err != nil || session != "authenticated" { c.Redirect(http.StatusFound, "/") c.Abort() return } c.Next() }) // Routes router.GET("/", func(c *gin.Context) { c.HTML(http.StatusOK, "login.html", nil) }) router.POST("/login", func(c *gin.Context) { name := c.PostForm("name") password := c.PostForm("password") if authenticateUser(db, name, hashPassword(password)) { // c.String(http.StatusOK, "Login successful!") // Création d'un cookie de session c.SetCookie("session", "authenticated", 3600, "/", "localhost", false, true) c.Redirect(http.StatusFound, "/dashboard") } else { c.String(http.StatusUnauthorized, "Invalid credentials") } }) router.GET("/dashboard", func(c *gin.Context) { users := fetchUsers(db) c.HTML(http.StatusOK, "dashboard.html", gin.H{"users": users}) }) router.POST("/edit/:id", func(c *gin.Context) { id := c.Param("id") name := c.PostForm("name") givenName := c.PostForm("givenname") sn := c.PostForm("sn") mail := c.PostForm("mail") sshkeys := c.PostForm("sshkeys") updateUser(db, id, name, givenName, sn, mail, sshkeys) c.Redirect(http.StatusFound, "/dashboard") }) router.GET("/edit/:id", func(c *gin.Context) { id := c.Param("id") user := fetchUserByID(db, id) groups, err := fetchLDAPGroups(db) if err != nil { log.Println("Erreur lors de la récupération des groupes :", err) c.String(http.StatusInternalServerError, "Erreur lors de la récupération des groupes") return } c.HTML(http.StatusOK, "edit.html", gin.H{ "user": user, "groups": groups, }) }) // Route GET pour afficher le formulaire de création router.GET("/new", func(c *gin.Context) { // Rendre la page "edit.html" avec un utilisateur vide c.HTML(http.StatusOK, "edit.html", gin.H{"user": map[string]string{ "ID": "", "Name": "", "GivenName": "", "SN": "", "Mail": "", "SSHKeys": "", }}) }) /* // Route POST pour insérer un nouvel utilisateur router.POST("/new", func(c *gin.Context) { name := c.PostForm("name") givenName := c.PostForm("givenname") sn := c.PostForm("sn") mail := c.PostForm("mail") sshkeys := c.PostForm("sshkeys") // Appeler la fonction pour récupérer le dernier uidnumber lastUID, err := getLastUIDNumber(db) if err != nil { log.Fatal(err) } nextUID := lastUID+1 // Génération automatique d'un mot de passe aléatoire randomPassword := generateRandomPassword(32) hashedPassword := hashPassword(randomPassword) // Insérer dans la base de données _, err := db.Exec(` INSERT INTO users (name, uidnumber, givenname, sn, mail, passsha256, sshkeys) VALUES (?, ?, ?, ?, ?, ?, ?)`, name, nextUID, givenName, sn, mail, hashedPassword, sshkeys) if err != nil { log.Println("Erreur lors de l'insertion :", err) c.String(http.StatusInternalServerError, "Erreur lors de l'ajout de l'utilisateur") return } // Redirection vers le tableau de bord après la création c.Redirect(http.StatusFound, "/dashboard") }) router.POST("/update/:id", func(c *gin.Context) { userID := c.Param("id") // Récupérer les valeurs du formulaire name := c.PostForm("name") sn := c.PostForm("sn") givenname := c.PostForm("givenname") mail := c.PostForm("mail") primarygroup := c.PostForm("group") // Convertir groupID en entier groupIDInt, err := strconv.Atoi(groupID) if err != nil { log.Println("Erreur lors de la conversion du groupID:", err) c.String(http.StatusBadRequest, "Erreur dans la conversion du groupID") return } // Mettre à jour l'utilisateur dans la base de données _, err = db.Exec(` UPDATE users SET name = ?, sn = ?, givenname = ?, mail = ?, primarygroup = ? WHERE id = ?`, name, sn, givenname, mail, groupIDInt, userID) if err != nil { log.Println("Erreur lors de la mise à jour de l'utilisateur :", err) c.String(http.StatusInternalServerError, "Erreur lors de la mise à jour de l'utilisateur") return } // Rediriger vers la page dashboard après mise à jour c.Redirect(http.StatusFound, "/dashboard") }) */ /* // Route pour afficher la liste des utilisateurs router.GET("/users", func(c *gin.Context) { users := fetchUsers(db) // Assurez-vous de disposer de la fonction fetchUsers qui retourne les utilisateurs if err != nil { log.Println("Erreur lors de la récupération des utilisateurs :", err) c.String(http.StatusInternalServerError, "Erreur lors de la récupération des utilisateurs") return } c.HTML(http.StatusOK, "users.html", gin.H{ "users": users, }) }) */ // Route pour afficher la liste des groupes router.GET("/groups", func(c *gin.Context) { groups, err := fetchLDAPGroups(db) // Utilisez la fonction fetchLDAPGroups que vous avez déjà définie if err != nil { log.Println("Erreur lors de la récupération des groupes :", err) c.String(http.StatusInternalServerError, "Erreur lors de la récupération des groupes") return } c.HTML(http.StatusOK, "groups.html", gin.H{ "groups": groups, }) }) // logout router.GET("/logout", func(c *gin.Context) { c.SetCookie("session", "", -1, "/", "localhost", false, true) c.Redirect(http.StatusFound, "/") }) // Start the server router.Run(":8080") }