-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathsimplecert_test.go
153 lines (123 loc) · 3.82 KB
/
simplecert_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
146
147
148
149
150
151
152
153
//
// simplecert
//
// Created by Philipp Mieden
// Contact: [email protected]
// Copyright © 2018 bestbytes. All rights reserved.
//
package simplecert
import (
"context"
"fmt"
"log"
"net/http"
"os"
"testing"
"time"
"github.com/foomo/tlsconfig"
)
var stopAfterNumRenews = 4
// testing with pebble ACME server:
// 1. go get github.com/letsencrypt/pebble and move into pebble project directory
// 2. add cert to trust store
// $ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain test/certs/pebble.minica.pem
// 3. start pebble ACME testing service, disable nonce rejection and challenge verification, as well as authz reuse:
// $ PEBBLE_AUTHZREUSE=0 PEBBLE_WFE_NONCEREJECT=0 PEBBLE_VA_ALWAYS_VALID=1 pebble -config ./test/config/pebble-config.json
// 4. point test domain to localhost in /etc/hosts
// 127.0.0.1 mytestdomain.com
func TestRenewal(t *testing.T) {
// pebble wont store any information on the file system
// so we need to reset all state before contacting it initially
// or we will be greeted with an error stating that the account https://0.0.0.0:14000/my-account/1 was not found
_ = os.RemoveAll("simplecert")
var (
certReloader *CertReloader
err error
numRenews int
ctx, cancel = context.WithCancel(context.Background())
// init strict tlsConfig
tlsconf = tlsconfig.NewServerTLSConfig(tlsconfig.TLSModeServerStrict)
makeServer = func() *http.Server {
return &http.Server{
Addr: ":5001",
Handler: nil, // http.DefaultServeMux
TLSConfig: tlsconf,
}
}
// init server
srv = makeServer()
// init simplecert configuration
cfg = Default
)
// configure
cfg.Domains = []string{"mytestdomain.com"}
cfg.CacheDir = "simplecert"
cfg.SSLEmail = "[email protected]"
cfg.DirectoryURL = "https://127.0.0.1:14000/dir"
cfg.RenewBefore = int((90 * 24 * time.Hour) - 1*time.Minute) // renew if older than 1 minute after initial retrieval
cfg.CheckInterval = 20 * time.Second // check every 20 seconds
cfg.CacheDir = "simplecert"
cfg.WillRenewCertificate = func() {
// stop server
cancel()
}
cfg.DidRenewCertificate = func() {
numRenews++
if numRenews == stopAfterNumRenews {
os.Exit(0)
}
// restart server: both context and server instance need to be recreated!
ctx, cancel = context.WithCancel(context.Background())
srv = makeServer()
// force reload the updated cert from disk
certReloader.ReloadNow()
go serve(ctx, srv)
}
// init config
certReloader, err = Init(cfg, func() {
os.Exit(0)
})
if err != nil {
log.Fatal("simplecert init failed: ", err)
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("hello"))
})
// redirect HTTP to HTTPS
log.Println("starting HTTP Listener on Port 80")
go func() {
errRedirect := http.ListenAndServe(":80", http.HandlerFunc(Redirect))
if errRedirect != nil {
log.Fatal("[FATAL] simplecert: redirect handler failed: ", errRedirect)
}
}()
// enable hot reload
tlsconf.GetCertificate = certReloader.GetCertificateFunc()
// start serving
log.Println("will serve at: https://" + cfg.Domains[0])
serve(ctx, srv)
fmt.Println("waiting forever")
<-make(chan bool)
}
func serve(ctx context.Context, srv *http.Server) {
// lets go
go func() {
if err := srv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %+s\n", err)
}
}()
log.Printf("server started")
<-ctx.Done()
log.Printf("server stopped")
ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer func() {
cancel()
}()
err := srv.Shutdown(ctxShutDown)
if err == http.ErrServerClosed {
log.Printf("server exited properly")
} else if err != nil {
log.Printf("server encountered an error on exit: %+s\n", err)
}
}