mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-04 06:43:45 +08:00
392f1d70eb
If the password arg starts with htpasswd=, then the rest is treated as the file name of the htpasswd file, and used for md5 and sha1 hashes.
144 lines
3.7 KiB
Go
144 lines
3.7 KiB
Go
package basicauth
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/mholt/caddy/middleware"
|
|
)
|
|
|
|
func TestBasicAuth(t *testing.T) {
|
|
|
|
rw := BasicAuth{
|
|
Next: middleware.HandlerFunc(contentHandler),
|
|
Rules: []Rule{
|
|
{Username: "test", Password: PlainMatcher("ttest"), Resources: []string{"/testing"}},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
from string
|
|
result int
|
|
cred string
|
|
}{
|
|
{"/testing", http.StatusUnauthorized, "ttest:test"},
|
|
{"/testing", http.StatusOK, "test:ttest"},
|
|
{"/testing", http.StatusUnauthorized, ""},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
|
|
req, err := http.NewRequest("GET", test.from, nil)
|
|
if err != nil {
|
|
t.Fatalf("Test %d: Could not create HTTP request %v", i, err)
|
|
}
|
|
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(test.cred))
|
|
req.Header.Set("Authorization", auth)
|
|
|
|
rec := httptest.NewRecorder()
|
|
result, err := rw.ServeHTTP(rec, req)
|
|
if err != nil {
|
|
t.Fatalf("Test %d: Could not ServeHTTP %v", i, err)
|
|
}
|
|
if result != test.result {
|
|
t.Errorf("Test %d: Expected Header '%d' but was '%d'",
|
|
i, test.result, result)
|
|
}
|
|
if result == http.StatusUnauthorized {
|
|
headers := rec.Header()
|
|
if val, ok := headers["Www-Authenticate"]; ok {
|
|
if val[0] != "Basic" {
|
|
t.Errorf("Test %d, Www-Authenticate should be %s provided %s", i, "Basic", val[0])
|
|
}
|
|
} else {
|
|
t.Errorf("Test %d, should provide a header Www-Authenticate", i)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestMultipleOverlappingRules(t *testing.T) {
|
|
rw := BasicAuth{
|
|
Next: middleware.HandlerFunc(contentHandler),
|
|
Rules: []Rule{
|
|
{Username: "t", Password: PlainMatcher("p1"), Resources: []string{"/t"}},
|
|
{Username: "t1", Password: PlainMatcher("p2"), Resources: []string{"/t/t"}},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
from string
|
|
result int
|
|
cred string
|
|
}{
|
|
{"/t", http.StatusOK, "t:p1"},
|
|
{"/t/t", http.StatusOK, "t:p1"},
|
|
{"/t/t", http.StatusOK, "t1:p2"},
|
|
{"/a", http.StatusOK, "t1:p2"},
|
|
{"/t/t", http.StatusUnauthorized, "t1:p3"},
|
|
{"/t", http.StatusUnauthorized, "t1:p2"},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
|
|
req, err := http.NewRequest("GET", test.from, nil)
|
|
if err != nil {
|
|
t.Fatalf("Test %d: Could not create HTTP request %v", i, err)
|
|
}
|
|
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(test.cred))
|
|
req.Header.Set("Authorization", auth)
|
|
|
|
rec := httptest.NewRecorder()
|
|
result, err := rw.ServeHTTP(rec, req)
|
|
if err != nil {
|
|
t.Fatalf("Test %d: Could not ServeHTTP %v", i, err)
|
|
}
|
|
if result != test.result {
|
|
t.Errorf("Test %d: Expected Header '%d' but was '%d'",
|
|
i, test.result, result)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func contentHandler(w http.ResponseWriter, r *http.Request) (int, error) {
|
|
fmt.Fprintf(w, r.URL.String())
|
|
return http.StatusOK, nil
|
|
}
|
|
|
|
func TestHtpasswd(t *testing.T) {
|
|
htpasswdPasswd := "IedFOuGmTpT8"
|
|
htpasswdFile := `sha1:{SHA}dcAUljwz99qFjYR0YLTXx0RqLww=
|
|
md5:$apr1$l42y8rex$pOA2VJ0x/0TwaFeAF9nX61`
|
|
|
|
htfh, err := ioutil.TempFile("", "basicauth-")
|
|
if err != nil {
|
|
t.Skipf("Error creating temp file (%v), will skip htpassword test")
|
|
return
|
|
}
|
|
if _, err = htfh.Write([]byte(htpasswdFile)); err != nil {
|
|
t.Fatalf("write htpasswd file %q: %v", htfh.Name(), err)
|
|
}
|
|
htfh.Close()
|
|
defer os.Remove(htfh.Name())
|
|
|
|
for i, username := range []string{"sha1", "md5"} {
|
|
rule := Rule{Username: username, Resources: []string{"/testing"}}
|
|
if rule.Password, err = GetHtpasswdMatcher(htfh.Name(), rule.Username); err != nil {
|
|
t.Fatalf("GetHtpasswdMatcher(%q, %q): %v", htfh.Name(), rule.Username, err)
|
|
}
|
|
t.Logf("%d. username=%q password=%v", i, rule.Username, rule.Password)
|
|
if !rule.Password(htpasswdPasswd) || rule.Password(htpasswdPasswd+"!") {
|
|
t.Errorf("%d (%s) password does not match.", i, rule.Username)
|
|
}
|
|
}
|
|
}
|