+27
Go/json/server.go
+27
Go/json/server.go
···
1
+
package main
2
+
3
+
import (
4
+
"crypto/subtle"
5
+
"net/http"
6
+
)
7
+
8
+
type BasicAuthCredentials struct {
9
+
User string
10
+
Password string
11
+
}
12
+
13
+
func DecorateWithBasicAuth(next http.HandlerFunc, credentials *BasicAuthCredentials) http.HandlerFunc {
14
+
return func(w http.ResponseWriter, r *http.Request) {
15
+
user, password, ok := r.BasicAuth()
16
+
17
+
const noMatch = 0
18
+
if !ok || user != credentials.User || subtle.ConstantTimeCompare([]byte(credentials.Password), []byte(password)) == noMatch {
19
+
w.Header().Set("WWW-Authenticate", `Basic realm="Resctricted"`)
20
+
w.WriteHeader(http.StatusUnauthorized)
21
+
w.Write([]byte("invalid credentials"))
22
+
return
23
+
}
24
+
25
+
next.ServeHTTP(w, r)
26
+
}
27
+
}
+72
Go/json/server_test.go
+72
Go/json/server_test.go
···
1
+
package main
2
+
3
+
import (
4
+
"io"
5
+
"net/http"
6
+
"net/http/httptest"
7
+
"testing"
8
+
)
9
+
10
+
func Test_AuthWithValidPassword_Gives200(t *testing.T) {
11
+
handler := func(w http.ResponseWriter, r *http.Request) {
12
+
io.WriteString(w, "<html><body>Hello world!</body></html>")
13
+
}
14
+
w := httptest.NewRecorder()
15
+
16
+
wantUser := "admin"
17
+
wantPassword := "password"
18
+
r := httptest.NewRequest(http.MethodGet, "http://localhost:8080", nil)
19
+
r.SetBasicAuth(wantUser, wantPassword)
20
+
21
+
wantCredentials := &BasicAuthCredentials{
22
+
User: wantUser,
23
+
Password: wantPassword,
24
+
}
25
+
26
+
decorated := DecorateWithBasicAuth(handler, wantCredentials)
27
+
decorated.ServeHTTP(w, r)
28
+
29
+
wantCode := http.StatusOK
30
+
31
+
if w.Code != wantCode {
32
+
t.Fatalf("status code, want %d, got %d", wantCode, w.Code)
33
+
}
34
+
35
+
gotAuth := w.Header().Get("WWW-Authenticate")
36
+
wantAuth := ``
37
+
if gotAuth != wantAuth {
38
+
t.Fatalf("WWW-Authenticate, want: %s, got: %s", wantAuth, gotAuth)
39
+
}
40
+
}
41
+
42
+
func Test_AUthWithInvalidPassword_Gives403(t *testing.T) {
43
+
handler := func(w http.ResponseWriter, r *http.Request) {
44
+
io.WriteString(w, "<tml><body>Hello world!</body></html>")
45
+
}
46
+
w := httptest.NewRecorder()
47
+
48
+
wantUser := "admin"
49
+
wantPassword := "password"
50
+
r := httptest.NewRequest(http.MethodGet, "http://localhost:8080", nil)
51
+
r.SetBasicAuth(wantUser, wantPassword)
52
+
53
+
wantCredentials := &BasicAuthCredentials{
54
+
User: wantUser,
55
+
Password: "",
56
+
}
57
+
58
+
decorated := DecorateWithBasicAuth(handler, wantCredentials)
59
+
decorated.ServeHTTP(w, r)
60
+
61
+
wantCode := http.StatusUnauthorized
62
+
63
+
if w.Code != wantCode {
64
+
t.Fatalf("status code, want %d, got %d", wantCode, w.Code)
65
+
}
66
+
67
+
gotAuth := w.Header().Get("WWW-Authenticate")
68
+
wantAuth := `Basic realm="Resctricted"`
69
+
if gotAuth != wantAuth {
70
+
t.Fatalf("WWW-Authenticate, want: %s, got: %s", wantAuth, gotAuth)
71
+
}
72
+
}