package main import ( "bufio" "fmt" "log" "net/http" "os" "strings" "github.com/gin-gonic/gin" "gitlab.com/nyarla/go-crypt" ) func Htpassword(file string) func(c *gin.Context) { htpasswd := &Htpasswd{} log.Println("Reading htpasswd file...") var err error if htpasswd, err = NewHtpasswd(file); htpasswd == nil { log.Fatal("Unable to parse htpasswd:", err) } return func(c *gin.Context) { username, password, ok := c.Request.BasicAuth() if !ok { c.Writer.Header().Add("WWW-Authenticate", "Basic realm=\"FIC challenge Dashboard\"") c.AbortWithError(http.StatusUnauthorized, fmt.Errorf("Please login")) return } if !htpasswd.Authenticate(username, password) { c.Writer.Header().Add("WWW-Authenticate", "Basic realm=\"FIC challenge Dashboard\"") c.AbortWithError(http.StatusUnauthorized, fmt.Errorf("Not authorized")) return } c.Next() } } type Htpasswd struct { entries map[string]string } func NewHtpasswd(path string) (*Htpasswd, error) { if fd, err := os.Open(path); err != nil { return nil, err } else { defer fd.Close() htpasswd := Htpasswd{ map[string]string{}, } scanner := bufio.NewScanner(fd) for scanner.Scan() { line := strings.SplitN(strings.TrimSpace(scanner.Text()), ":", 2) if len(line) == 2 && len(line[1]) > 2 { htpasswd.entries[line[0]] = line[1] } } if err := scanner.Err(); err != nil { return nil, err } return &htpasswd, nil } } func (h Htpasswd) Authenticate(username, password string) bool { if hash, ok := h.entries[username]; !ok { return false } else if crypt.Crypt(password, hash[:2]) != hash { return false } else { return true } }