...
1 package htpasswd
2
3 import (
4 "bufio"
5 "fmt"
6 "io"
7 "strings"
8
9 "github.com/docker/distribution/registry/auth"
10
11 "golang.org/x/crypto/bcrypt"
12 )
13
14
15
16 type htpasswd struct {
17 entries map[string][]byte
18 }
19
20
21 func newHTPasswd(rd io.Reader) (*htpasswd, error) {
22 entries, err := parseHTPasswd(rd)
23 if err != nil {
24 return nil, err
25 }
26
27 return &htpasswd{entries: entries}, nil
28 }
29
30
31
32 func (htpasswd *htpasswd) authenticateUser(username string, password string) error {
33 credentials, ok := htpasswd.entries[username]
34 if !ok {
35
36 bcrypt.CompareHashAndPassword([]byte{}, []byte(password))
37
38 return auth.ErrAuthenticationFailure
39 }
40
41 err := bcrypt.CompareHashAndPassword(credentials, []byte(password))
42 if err != nil {
43 return auth.ErrAuthenticationFailure
44 }
45
46 return nil
47 }
48
49
50
51
52 func parseHTPasswd(rd io.Reader) (map[string][]byte, error) {
53 entries := map[string][]byte{}
54 scanner := bufio.NewScanner(rd)
55 var line int
56 for scanner.Scan() {
57 line++
58 t := strings.TrimSpace(scanner.Text())
59
60 if len(t) < 1 {
61 continue
62 }
63
64
65 if t[0] == '#' {
66 continue
67 }
68
69 i := strings.Index(t, ":")
70 if i < 0 || i >= len(t) {
71 return nil, fmt.Errorf("htpasswd: invalid entry at line %d: %q", line, scanner.Text())
72 }
73
74 entries[t[:i]] = []byte(t[i+1:])
75 }
76
77 if err := scanner.Err(); err != nil {
78 return nil, err
79 }
80
81 return entries, nil
82 }
83
View as plain text