123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- 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")
- }
|