forked from go-acme/lego
-
Notifications
You must be signed in to change notification settings - Fork 0
/
simple_http_challenge_test.go
145 lines (124 loc) · 4.63 KB
/
simple_http_challenge_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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package acme
import (
"crypto/rsa"
"crypto/tls"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/square/go-jose"
)
func TestSimpleHTTPCanSolve(t *testing.T) {
challenge := &simpleHTTPChallenge{}
// determine public ip
resp, err := http.Get("https://icanhazip.com/")
if err != nil {
t.Errorf("Could not get public IP -> %v", err)
}
defer resp.Body.Close()
ip, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("Could not get public IP -> %v", err)
}
ipStr := string(ip)
if expected, actual := false, challenge.CanSolve("google.com"); expected != actual {
t.Errorf("Expected CanSolve to return %t for domain 'google.com' but was %t", expected, actual)
}
localResolv := strings.Replace(ipStr, "\n", "", -1) + ".xip.io"
if expected, actual := true, challenge.CanSolve(localResolv); expected != actual {
t.Errorf("Expected CanSolve to return %t for domain 'localhost' but was %t", expected, actual)
}
}
func TestSimpleHTTP(t *testing.T) {
privKey, err := generatePrivateKey(rsakey, 512)
if err != nil {
t.Errorf("Could not generate public key -> %v", err)
}
jws := &jws{privKey: privKey.(*rsa.PrivateKey)}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Replay-Nonce", "12345")
}))
solver := &simpleHTTPChallenge{jws: jws}
clientChallenge := challenge{Type: "simpleHttp", Status: "pending", URI: ts.URL, Token: "123456789"}
// validate error on non-root bind to 443
if err = solver.Solve(clientChallenge, "test.domain"); err == nil {
t.Error("BIND: Expected Solve to return an error but the error was nil.")
}
// Validate error on unexpected state
solver.optPort = "23456"
if err = solver.Solve(clientChallenge, "test.domain"); err == nil {
t.Error("UNEXPECTED: Expected Solve to return an error but the error was nil.")
}
// Validate error on invalid status
ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Replay-Nonce", "12345")
failed := challenge{Type: "simpleHttp", Status: "invalid", URI: ts.URL, Token: "1234567810"}
jsonBytes, _ := json.Marshal(&failed)
w.Write(jsonBytes)
})
clientChallenge.Token = "1234567810"
if err = solver.Solve(clientChallenge, "test.domain"); err == nil {
t.Error("FAILED: Expected Solve to return an error but the error was nil.")
}
// Validate no error on valid response
ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Replay-Nonce", "12345")
valid := challenge{Type: "simpleHttp", Status: "valid", URI: ts.URL, Token: "1234567811"}
jsonBytes, _ := json.Marshal(&valid)
w.Write(jsonBytes)
})
clientChallenge.Token = "1234567811"
if err = solver.Solve(clientChallenge, "test.domain"); err != nil {
t.Errorf("VALID: Expected Solve to return no error but the error was -> %v", err)
}
// Validate server on port 23456 which responds appropriately
clientChallenge.Token = "1234567812"
ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var request challenge
w.Header().Add("Replay-Nonce", "12345")
if r.Method == "HEAD" {
return
}
clientJws, _ := ioutil.ReadAll(r.Body)
j, err := jose.ParseSigned(string(clientJws))
if err != nil {
t.Errorf("Client sent invalid JWS to the server.\n\t%v", err)
return
}
output, err := j.Verify(&privKey.(*rsa.PrivateKey).PublicKey)
if err != nil {
t.Errorf("Unable to verify client data -> %v", err)
}
json.Unmarshal(output, &request)
transport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
client := &http.Client{Transport: transport}
reqURL := "https://localhost:23456/.well-known/acme-challenge/" + clientChallenge.Token
t.Logf("Request URL is: %s", reqURL)
req, _ := http.NewRequest("GET", reqURL, nil)
req.Host = "test.domain"
resp, err := client.Do(req)
if err != nil {
t.Errorf("Expected the solver to listen on port 23456 -> %v", err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
bodyStr := string(body)
clientResponse, err := jose.ParseSigned(bodyStr)
if err != nil {
t.Errorf("Client answered with invalid JWS.\n\t%v", err)
return
}
_, err = clientResponse.Verify(&privKey.(*rsa.PrivateKey).PublicKey)
if err != nil {
t.Errorf("Unable to verify client data -> %v", err)
}
valid := challenge{Type: "simpleHttp", Status: "valid", URI: ts.URL, Token: "1234567812"}
jsonBytes, _ := json.Marshal(&valid)
w.Write(jsonBytes)
})
if err = solver.Solve(clientChallenge, "test.domain"); err != nil {
t.Errorf("VALID: Expected Solve to return no error but the error was -> %v", err)
}
}