main.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. package main
  2. import (
  3. "crypto/sha256"
  4. "crypto/rand"
  5. "math/big"
  6. "database/sql"
  7. "encoding/hex"
  8. "log"
  9. // "strconv"
  10. "net/http"
  11. "github.com/gin-gonic/gin"
  12. _ "github.com/mattn/go-sqlite3"
  13. )
  14. type User struct {
  15. ID int
  16. Name string
  17. UIDNumber int
  18. PrimaryGroup int
  19. OtherGroups string
  20. GivenName string
  21. SN string
  22. Mail string
  23. LoginShell string
  24. HomeDirectory string
  25. Disabled int
  26. PassSHA256 string
  27. OTPSecret string
  28. YubiKey string
  29. SSHKeys string
  30. CustAttr string
  31. }
  32. // Structure représentant un groupe LDAP
  33. type LDAPGroup struct {
  34. ID int `json:"id"`
  35. Name string `json:"name"`
  36. GIDNumber int `json:"gidnumber"`
  37. }
  38. func createTable(db *sql.DB) {
  39. query := `
  40. CREATE TABLE IF NOT EXISTS users (
  41. id INTEGER PRIMARY KEY,
  42. name TEXT NOT NULL,
  43. uidnumber INTEGER NOT NULL,
  44. primarygroup INTEGER NOT NULL,
  45. othergroups TEXT DEFAULT '',
  46. givenname TEXT DEFAULT '',
  47. sn TEXT DEFAULT '',
  48. mail TEXT DEFAULT '',
  49. loginshell TEXT DEFAULT '',
  50. homedirectory TEXT DEFAULT '',
  51. disabled SMALLINT DEFAULT 0,
  52. passsha256 TEXT DEFAULT '',
  53. otpsecret TEXT DEFAULT '',
  54. yubikey TEXT DEFAULT '',
  55. sshkeys TEXT DEFAULT '',
  56. custattr TEXT DEFAULT '{}'
  57. );
  58. `
  59. _, err := db.Exec(query)
  60. if err != nil {
  61. log.Fatalf("Failed to create table: %v", err)
  62. }
  63. }
  64. func hashPassword(password string) string {
  65. hash := sha256.New()
  66. hash.Write([]byte(password))
  67. return hex.EncodeToString(hash.Sum(nil))
  68. }
  69. func generateRandomPassword(maxLength int) string {
  70. const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=<>?/|"
  71. password := make([]byte, maxLength)
  72. for i := range password {
  73. charIndex, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
  74. password[i] = charset[charIndex.Int64()]
  75. }
  76. return string(password)
  77. }
  78. func generatePasswordSHA256(maxLength int) string {
  79. randomPassword := generateRandomPassword(maxLength)
  80. return hashPassword(randomPassword)
  81. }
  82. func authenticateUser(db *sql.DB, name, hashedPassword string) bool {
  83. var user User
  84. query := "SELECT * FROM users WHERE name = ? AND passsha256 = ?"
  85. err := db.QueryRow(query, name, hashedPassword).Scan(
  86. &user.ID, &user.Name, &user.UIDNumber, &user.PrimaryGroup, &user.OtherGroups,
  87. &user.GivenName, &user.SN, &user.Mail, &user.LoginShell, &user.HomeDirectory,
  88. &user.Disabled, &user.PassSHA256, &user.OTPSecret, &user.YubiKey,
  89. &user.SSHKeys, &user.CustAttr,
  90. )
  91. return err == nil
  92. }
  93. // Fonction pour récupérer le dernier `uidnumber` dans la table `users`
  94. func getLastUIDNumber(db *sql.DB) (int, error) {
  95. // Requête SQL pour récupérer le dernier uidnumber
  96. var lastUIDNumber int
  97. err := db.QueryRow("SELECT MAX(uidnumber) FROM users").Scan(&lastUIDNumber)
  98. if err != nil {
  99. if err == sql.ErrNoRows {
  100. // Si aucune ligne n'est trouvée, retourner 0
  101. return 0, nil
  102. }
  103. return 0, err
  104. }
  105. return lastUIDNumber, nil
  106. }
  107. func createUser(db *sql.DB, name, password string) bool {
  108. hashedPassword := hashPassword(password)
  109. query := "INSERT INTO users (name, passsha256) VALUES (?, ?)"
  110. _, err := db.Exec(query, name, hashedPassword)
  111. return err == nil
  112. }
  113. func fetchUsers(db *sql.DB) []User {
  114. query := "SELECT id, name, sn, givenname, mail FROM users"
  115. rows, err := db.Query(query)
  116. if err != nil {
  117. log.Fatalf("Failed to fetch users: %v", err)
  118. }
  119. defer rows.Close()
  120. var users []User
  121. for rows.Next() {
  122. var user User
  123. err := rows.Scan(&user.ID, &user.Name, &user.SN, &user.GivenName, &user.Mail)
  124. if err != nil {
  125. log.Fatalf("Failed to scan user: %v", err)
  126. }
  127. users = append(users, user)
  128. }
  129. return users
  130. }
  131. func fetchUserByID(db *sql.DB, id string) User {
  132. query := "SELECT * FROM users WHERE id = ?"
  133. var user User
  134. err := db.QueryRow(query, id).Scan(
  135. &user.ID, &user.Name, &user.UIDNumber, &user.PrimaryGroup, &user.OtherGroups,
  136. &user.GivenName, &user.SN, &user.Mail, &user.LoginShell, &user.HomeDirectory,
  137. &user.Disabled, &user.PassSHA256, &user.OTPSecret, &user.YubiKey,
  138. &user.SSHKeys, &user.CustAttr,
  139. )
  140. if err != nil {
  141. log.Fatalf("Failed to fetch user: %v", err)
  142. }
  143. return user
  144. }
  145. func updateUser(db *sql.DB, id, name, givenName, sn, mail string, sshkeys string) {
  146. query := "UPDATE users SET name = ?, givenname = ?, sn = ?, mail = ?, sshkeys = ? WHERE id = ?"
  147. _, err := db.Exec(query, name, givenName, sn, mail, sshkeys, id)
  148. if err != nil {
  149. log.Fatalf("Failed to update user: %v", err)
  150. }
  151. }
  152. // Fonction pour récupérer tous les groupes LDAP
  153. func fetchLDAPGroups(db *sql.DB) ([]LDAPGroup, error) {
  154. // Préparer la requête SQL pour récupérer les groupes
  155. rows, err := db.Query("SELECT id, name, gidnumber FROM ldapgroups")
  156. if err != nil {
  157. return nil, err
  158. }
  159. defer rows.Close()
  160. // Initialiser un tableau pour stocker les groupes
  161. var groups []LDAPGroup
  162. // Parcourir les résultats de la requête
  163. for rows.Next() {
  164. var group LDAPGroup
  165. if err := rows.Scan(&group.ID, &group.Name, &group.GIDNumber); err != nil {
  166. return nil, err
  167. }
  168. // Ajouter le groupe à la liste
  169. groups = append(groups, group)
  170. }
  171. // Vérifier si des erreurs sont survenues lors du parcours des lignes
  172. if err := rows.Err(); err != nil {
  173. return nil, err
  174. }
  175. return groups, nil
  176. }
  177. func main() {
  178. // Initialize database connection
  179. db, err := sql.Open("sqlite3", "./users.db")
  180. if err != nil {
  181. log.Fatal(err)
  182. }
  183. defer db.Close()
  184. // Create table if it doesn't exist
  185. createTable(db)
  186. // Initialize Gin router
  187. router := gin.Default()
  188. // Serve HTML templates
  189. router.LoadHTMLGlob("templates/*")
  190. // Middleware for session authentication
  191. router.Use(func(c *gin.Context) {
  192. // Skip authentication check for login page
  193. if c.Request.URL.Path == "/" || c.Request.URL.Path == "/login" {
  194. c.Next()
  195. return
  196. }
  197. // Check if user is authenticated
  198. session, err := c.Cookie("session")
  199. if err != nil || session != "authenticated" {
  200. c.Redirect(http.StatusFound, "/")
  201. c.Abort()
  202. return
  203. }
  204. c.Next()
  205. })
  206. // Routes
  207. router.GET("/", func(c *gin.Context) {
  208. c.HTML(http.StatusOK, "login.html", nil)
  209. })
  210. router.POST("/login", func(c *gin.Context) {
  211. name := c.PostForm("name")
  212. password := c.PostForm("password")
  213. if authenticateUser(db, name, hashPassword(password)) {
  214. // c.String(http.StatusOK, "Login successful!")
  215. // Création d'un cookie de session
  216. c.SetCookie("session", "authenticated", 3600, "/", "localhost", false, true)
  217. c.Redirect(http.StatusFound, "/dashboard")
  218. } else {
  219. c.String(http.StatusUnauthorized, "Invalid credentials")
  220. }
  221. })
  222. router.GET("/dashboard", func(c *gin.Context) {
  223. users := fetchUsers(db)
  224. c.HTML(http.StatusOK, "dashboard.html", gin.H{"users": users})
  225. })
  226. router.POST("/edit/:id", func(c *gin.Context) {
  227. id := c.Param("id")
  228. name := c.PostForm("name")
  229. givenName := c.PostForm("givenname")
  230. sn := c.PostForm("sn")
  231. mail := c.PostForm("mail")
  232. sshkeys := c.PostForm("sshkeys")
  233. updateUser(db, id, name, givenName, sn, mail, sshkeys)
  234. c.Redirect(http.StatusFound, "/dashboard")
  235. })
  236. router.GET("/edit/:id", func(c *gin.Context) {
  237. id := c.Param("id")
  238. user := fetchUserByID(db, id)
  239. groups, err := fetchLDAPGroups(db)
  240. if err != nil {
  241. log.Println("Erreur lors de la récupération des groupes :", err)
  242. c.String(http.StatusInternalServerError, "Erreur lors de la récupération des groupes")
  243. return
  244. }
  245. c.HTML(http.StatusOK, "edit.html", gin.H{
  246. "user": user,
  247. "groups": groups,
  248. })
  249. })
  250. // Route GET pour afficher le formulaire de création
  251. router.GET("/new", func(c *gin.Context) {
  252. // Rendre la page "edit.html" avec un utilisateur vide
  253. c.HTML(http.StatusOK, "edit.html", gin.H{"user": map[string]string{
  254. "ID": "",
  255. "Name": "",
  256. "GivenName": "",
  257. "SN": "",
  258. "Mail": "",
  259. "SSHKeys": "",
  260. }})
  261. })
  262. /*
  263. // Route POST pour insérer un nouvel utilisateur
  264. router.POST("/new", func(c *gin.Context) {
  265. name := c.PostForm("name")
  266. givenName := c.PostForm("givenname")
  267. sn := c.PostForm("sn")
  268. mail := c.PostForm("mail")
  269. sshkeys := c.PostForm("sshkeys")
  270. // Appeler la fonction pour récupérer le dernier uidnumber
  271. lastUID, err := getLastUIDNumber(db)
  272. if err != nil {
  273. log.Fatal(err)
  274. }
  275. nextUID := lastUID+1
  276. // Génération automatique d'un mot de passe aléatoire
  277. randomPassword := generateRandomPassword(32)
  278. hashedPassword := hashPassword(randomPassword)
  279. // Insérer dans la base de données
  280. _, err := db.Exec(`
  281. INSERT INTO users (name, uidnumber, givenname, sn, mail, passsha256, sshkeys)
  282. VALUES (?, ?, ?, ?, ?, ?, ?)`, name, nextUID, givenName, sn, mail, hashedPassword, sshkeys)
  283. if err != nil {
  284. log.Println("Erreur lors de l'insertion :", err)
  285. c.String(http.StatusInternalServerError, "Erreur lors de l'ajout de l'utilisateur")
  286. return
  287. }
  288. // Redirection vers le tableau de bord après la création
  289. c.Redirect(http.StatusFound, "/dashboard")
  290. })
  291. router.POST("/update/:id", func(c *gin.Context) {
  292. userID := c.Param("id")
  293. // Récupérer les valeurs du formulaire
  294. name := c.PostForm("name")
  295. sn := c.PostForm("sn")
  296. givenname := c.PostForm("givenname")
  297. mail := c.PostForm("mail")
  298. primarygroup := c.PostForm("group")
  299. // Convertir groupID en entier
  300. groupIDInt, err := strconv.Atoi(groupID)
  301. if err != nil {
  302. log.Println("Erreur lors de la conversion du groupID:", err)
  303. c.String(http.StatusBadRequest, "Erreur dans la conversion du groupID")
  304. return
  305. }
  306. // Mettre à jour l'utilisateur dans la base de données
  307. _, err = db.Exec(`
  308. UPDATE users SET name = ?, sn = ?, givenname = ?, mail = ?, primarygroup = ?
  309. WHERE id = ?`, name, sn, givenname, mail, groupIDInt, userID)
  310. if err != nil {
  311. log.Println("Erreur lors de la mise à jour de l'utilisateur :", err)
  312. c.String(http.StatusInternalServerError, "Erreur lors de la mise à jour de l'utilisateur")
  313. return
  314. }
  315. // Rediriger vers la page dashboard après mise à jour
  316. c.Redirect(http.StatusFound, "/dashboard")
  317. })
  318. */
  319. /*
  320. // Route pour afficher la liste des utilisateurs
  321. router.GET("/users", func(c *gin.Context) {
  322. users := fetchUsers(db) // Assurez-vous de disposer de la fonction fetchUsers qui retourne les utilisateurs
  323. if err != nil {
  324. log.Println("Erreur lors de la récupération des utilisateurs :", err)
  325. c.String(http.StatusInternalServerError, "Erreur lors de la récupération des utilisateurs")
  326. return
  327. }
  328. c.HTML(http.StatusOK, "users.html", gin.H{
  329. "users": users,
  330. })
  331. })
  332. */
  333. // Route pour afficher la liste des groupes
  334. router.GET("/groups", func(c *gin.Context) {
  335. groups, err := fetchLDAPGroups(db) // Utilisez la fonction fetchLDAPGroups que vous avez déjà définie
  336. if err != nil {
  337. log.Println("Erreur lors de la récupération des groupes :", err)
  338. c.String(http.StatusInternalServerError, "Erreur lors de la récupération des groupes")
  339. return
  340. }
  341. c.HTML(http.StatusOK, "groups.html", gin.H{
  342. "groups": groups,
  343. })
  344. })
  345. // logout
  346. router.GET("/logout", func(c *gin.Context) {
  347. c.SetCookie("session", "", -1, "/", "localhost", false, true)
  348. c.Redirect(http.StatusFound, "/")
  349. })
  350. // Start the server
  351. router.Run(":8080")
  352. }