1 package htpasswd
2
3 import (
4 "bytes"
5 "io/ioutil"
6 "net/http"
7 "net/http/httptest"
8 "os"
9 "testing"
10
11 "github.com/docker/distribution/context"
12 "github.com/docker/distribution/registry/auth"
13 )
14
15 func TestBasicAccessController(t *testing.T) {
16 testRealm := "The-Shire"
17 testUsers := []string{"bilbo", "frodo", "MiShil", "DeokMan"}
18 testPasswords := []string{"baggins", "baggins", "새주", "공주님"}
19 testHtpasswdContent := `bilbo:{SHA}5siv5c0SHx681xU6GiSx9ZQryqs=
20 frodo:$2y$05$926C3y10Quzn/LnqQH86VOEVh/18T6RnLaS.khre96jLNL/7e.K5W
21 MiShil:$2y$05$0oHgwMehvoe8iAWS8I.7l.KoECXrwVaC16RPfaSCU5eVTFrATuMI2
22 DeokMan:공주님`
23
24 tempFile, err := ioutil.TempFile("", "htpasswd-test")
25 if err != nil {
26 t.Fatal("could not create temporary htpasswd file")
27 }
28 if _, err = tempFile.WriteString(testHtpasswdContent); err != nil {
29 t.Fatal("could not write temporary htpasswd file")
30 }
31
32 options := map[string]interface{}{
33 "realm": testRealm,
34 "path": tempFile.Name(),
35 }
36 ctx := context.Background()
37
38 accessController, err := newAccessController(options)
39 if err != nil {
40 t.Fatal("error creating access controller")
41 }
42
43 tempFile.Close()
44
45 var userNumber = 0
46
47 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
48 ctx := context.WithRequest(ctx, r)
49 authCtx, err := accessController.Authorized(ctx)
50 if err != nil {
51 switch err := err.(type) {
52 case auth.Challenge:
53 err.SetHeaders(r, w)
54 w.WriteHeader(http.StatusUnauthorized)
55 return
56 default:
57 t.Fatalf("unexpected error authorizing request: %v", err)
58 }
59 }
60
61 userInfo, ok := authCtx.Value(auth.UserKey).(auth.UserInfo)
62 if !ok {
63 t.Fatal("basic accessController did not set auth.user context")
64 }
65
66 if userInfo.Name != testUsers[userNumber] {
67 t.Fatalf("expected user name %q, got %q", testUsers[userNumber], userInfo.Name)
68 }
69
70 w.WriteHeader(http.StatusNoContent)
71 }))
72
73 client := &http.Client{
74 CheckRedirect: nil,
75 }
76
77 req, _ := http.NewRequest("GET", server.URL, nil)
78 resp, err := client.Do(req)
79
80 if err != nil {
81 t.Fatalf("unexpected error during GET: %v", err)
82 }
83 defer resp.Body.Close()
84
85
86 if resp.StatusCode != http.StatusUnauthorized {
87 t.Fatalf("unexpected non-fail response status: %v != %v", resp.StatusCode, http.StatusUnauthorized)
88 }
89
90 nonbcrypt := map[string]struct{}{
91 "bilbo": {},
92 "DeokMan": {},
93 }
94
95 for i := 0; i < len(testUsers); i++ {
96 userNumber = i
97 req, err := http.NewRequest("GET", server.URL, nil)
98 if err != nil {
99 t.Fatalf("error allocating new request: %v", err)
100 }
101
102 req.SetBasicAuth(testUsers[i], testPasswords[i])
103
104 resp, err = client.Do(req)
105 if err != nil {
106 t.Fatalf("unexpected error during GET: %v", err)
107 }
108 defer resp.Body.Close()
109
110 if _, ok := nonbcrypt[testUsers[i]]; ok {
111
112
113 if resp.StatusCode != http.StatusUnauthorized {
114 t.Fatalf("unexpected non-success response status: %v != %v for %s %s", resp.StatusCode, http.StatusUnauthorized, testUsers[i], testPasswords[i])
115 }
116 } else {
117
118 if resp.StatusCode != http.StatusNoContent {
119 t.Fatalf("unexpected non-success response status: %v != %v for %s %s", resp.StatusCode, http.StatusNoContent, testUsers[i], testPasswords[i])
120 }
121 }
122 }
123
124 }
125
126 func TestCreateHtpasswdFile(t *testing.T) {
127 tempFile, err := ioutil.TempFile("", "htpasswd-test")
128 if err != nil {
129 t.Fatalf("could not create temporary htpasswd file %v", err)
130 }
131 defer tempFile.Close()
132 options := map[string]interface{}{
133 "realm": "/auth/htpasswd",
134 "path": tempFile.Name(),
135 }
136
137 if _, err := newAccessController(options); err != nil {
138 t.Fatalf("error creating access controller %v", err)
139 }
140 content, err := ioutil.ReadAll(tempFile)
141 if err != nil {
142 t.Fatalf("failed to read file %v", err)
143 }
144 if !bytes.Equal([]byte{}, content) {
145 t.Fatalf("htpasswd file should not be populated %v", string(content))
146 }
147 if err := os.Remove(tempFile.Name()); err != nil {
148 t.Fatalf("failed to remove temp file %v", err)
149 }
150
151
152 if _, err := newAccessController(options); err != nil {
153 t.Fatalf("error creating access controller %v", err)
154 }
155 content, err = ioutil.ReadFile(tempFile.Name())
156 if err != nil {
157 t.Fatalf("failed to read file %v", err)
158 }
159 if !bytes.HasPrefix(content, []byte("docker:$2a$")) {
160 t.Fatalf("failed to find default user in file %s", string(content))
161 }
162 }
163
View as plain text