forked from golang/build
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauth_test.go
113 lines (102 loc) · 3.45 KB
/
auth_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gerrit
import (
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func md5str(text string) string {
h := md5.Sum([]byte(text))
return hex.EncodeToString(h[:])
}
func TestBasicAuth(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
expected := "User Password true"
u, p, ok := r.BasicAuth()
if expected != fmt.Sprintf("%s %s %t", u, p, ok) {
t.Errorf("Expected %s, got %s %s %t", expected, u, p, ok)
w.WriteHeader(http.StatusUnauthorized)
} else {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
// The JSON response begins with an XSRF-defeating header ")]}\n"
fmt.Fprintln(w, ")]}")
json.NewEncoder(w).Encode(AccountInfo{})
}
}))
defer ts.Close()
_, err := NewClient(
ts.URL,
BasicAuth("User", "Password"),
).GetAccountInfo(context.Background(), "self")
if err != nil {
t.Error(err)
}
}
func TestDigestAuth(t *testing.T) {
const (
user = "User"
pass = "Password"
nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093"
opaque = "5ccc069c403ebaf9f0171e9517f40e41"
realm = "Gerrit Code Review"
qop = "auth"
)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
header := r.Header.Get("Authorization")
if header == "" {
w.Header().Set("WWW-Authenticate", fmt.Sprintf(
`Digest realm="%s", qop="%s", nonce="%s", opaque="%s"`,
realm, qop, nonce, opaque,
))
w.WriteHeader(http.StatusUnauthorized)
} else {
parts := strings.SplitN(header, " ", 2)
parts = strings.Split(parts[1], ", ")
opts := make(map[string]string)
for _, part := range parts {
vals := strings.SplitN(part, "=", 2)
key := vals[0]
val := strings.Trim(vals[1], "\",")
opts[key] = val
}
// https://en.wikipedia.org/wiki/Digest_access_authentication#Example_with_explanation
// The "response" value is calculated in three steps, as follows.
// Where values are combined, they are delimited by colons.
// 1. The MD5 hash of the combined username, authentication realm and password is calculated.
// The result is referred to as HA1.
// 2. The MD5 hash of the combined method and digest URI is calculated, e.g. of "GET" and "/index.html".
// The result is referred to as HA2.
// 3. The MD5 hash of the combined HA1 result, server nonce (nonce), request counter (nc),
// client nonce (cnonce), quality of protection code (qop) and HA2 result is calculated.
// The result is the "response" value provided by the client.
ha1 := md5str(fmt.Sprintf("%s:%s:%s", user, realm, pass))
ha2 := md5str("GET:/a/accounts/self")
expected := md5str(fmt.Sprintf("%s:%s:%s:%s:%s:%s", ha1, nonce, opts["nc"], opts["cnonce"], qop, ha2))
if expected != opts["response"] {
t.Errorf("Expected %s, got %s", expected, opts["response"])
w.WriteHeader(http.StatusUnauthorized)
} else {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
// The JSON response begins with an XSRF-defeating header ")]}\n"
fmt.Fprintln(w, ")]}")
json.NewEncoder(w).Encode(AccountInfo{})
}
}
}))
defer ts.Close()
_, err := NewClient(
ts.URL,
DigestAuth(user, pass),
).GetAccountInfo(context.Background(), "self")
if err != nil {
t.Error(err)
}
}