forked from TrueCloudLab/lego
Merge pull request #21 from xenolf/logging
Make acme.Logger optional; otherwise use standard log.Logger
This commit is contained in:
commit
5ace5e130b
5 changed files with 37 additions and 40 deletions
|
@ -10,22 +10,23 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger is used to log errors; if nil, the default log.Logger is used.
|
// Logger is an optional custom logger.
|
||||||
var Logger *log.Logger
|
var Logger *log.Logger
|
||||||
|
|
||||||
// logger is an helper function to retrieve the available logger
|
// logf writes a log entry. It uses Logger if not
|
||||||
func logger() *log.Logger {
|
// nil, otherwise it uses the default log.Logger.
|
||||||
if Logger == nil {
|
func logf(format string, args ...interface{}) {
|
||||||
Logger = log.New(os.Stderr, "", log.LstdFlags)
|
if Logger != nil {
|
||||||
|
Logger.Printf(format, args...)
|
||||||
|
} else {
|
||||||
|
log.Printf(format, args...)
|
||||||
}
|
}
|
||||||
return Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User interface is to be implemented by users of this library.
|
// User interface is to be implemented by users of this library.
|
||||||
|
@ -105,7 +106,10 @@ func NewClient(caURL string, usr User, keyBits int, optPort string) (*Client, er
|
||||||
|
|
||||||
// Register the current account to the ACME server.
|
// Register the current account to the ACME server.
|
||||||
func (c *Client) Register() (*RegistrationResource, error) {
|
func (c *Client) Register() (*RegistrationResource, error) {
|
||||||
logger().Print("Registering account ... ")
|
if c == nil || c.user == nil {
|
||||||
|
return nil, errors.New("acme: cannot register a nil client or user")
|
||||||
|
}
|
||||||
|
logf("[INFO] acme: Registering account for %s", c.user.GetEmail())
|
||||||
|
|
||||||
regMsg := registrationMessage{
|
regMsg := registrationMessage{
|
||||||
Resource: "new-reg",
|
Resource: "new-reg",
|
||||||
|
@ -149,7 +153,7 @@ func (c *Client) Register() (*RegistrationResource, error) {
|
||||||
if links["next"] != "" {
|
if links["next"] != "" {
|
||||||
reg.NewAuthzURL = links["next"]
|
reg.NewAuthzURL = links["next"]
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("The server did not return enough information to proceed...")
|
return nil, errors.New("acme: The server did not return 'next' link to proceed")
|
||||||
}
|
}
|
||||||
|
|
||||||
return reg, nil
|
return reg, nil
|
||||||
|
@ -184,7 +188,12 @@ func (c *Client) AgreeToTOS() error {
|
||||||
// If bundle is true, the []byte contains both the issuer certificate and
|
// If bundle is true, the []byte contains both the issuer certificate and
|
||||||
// your issued certificate as a bundle.
|
// your issued certificate as a bundle.
|
||||||
func (c *Client) ObtainCertificates(domains []string, bundle bool) ([]CertificateResource, map[string]error) {
|
func (c *Client) ObtainCertificates(domains []string, bundle bool) ([]CertificateResource, map[string]error) {
|
||||||
logger().Print("Obtaining certificates...")
|
if bundle {
|
||||||
|
logf("[INFO] acme: Obtaining bundled certificates for %v", strings.Join(domains, ", "))
|
||||||
|
} else {
|
||||||
|
logf("[INFO] acme: Obtaining certificates for %v", strings.Join(domains, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
challenges, failures := c.getChallenges(domains)
|
challenges, failures := c.getChallenges(domains)
|
||||||
if len(challenges) == 0 {
|
if len(challenges) == 0 {
|
||||||
return nil, failures
|
return nil, failures
|
||||||
|
@ -199,7 +208,7 @@ func (c *Client) ObtainCertificates(domains []string, bundle bool) ([]Certificat
|
||||||
return nil, failures
|
return nil, failures
|
||||||
}
|
}
|
||||||
|
|
||||||
logger().Print("Validations succeeded. Getting certificates")
|
logf("[INFO] acme: Validations succeeded; requesting certificates")
|
||||||
|
|
||||||
certs, err := c.requestCertificates(challenges, bundle)
|
certs, err := c.requestCertificates(challenges, bundle)
|
||||||
for k, v := range err {
|
for k, v := range err {
|
||||||
|
@ -263,7 +272,7 @@ func (c *Client) RenewCertificate(cert CertificateResource, revokeOld bool, bund
|
||||||
|
|
||||||
// This is just meant to be informal for the user.
|
// This is just meant to be informal for the user.
|
||||||
timeLeft := x509Cert.NotAfter.Sub(time.Now().UTC())
|
timeLeft := x509Cert.NotAfter.Sub(time.Now().UTC())
|
||||||
logger().Printf("[%s] Trying to renew certificate with %d hours remaining.", cert.Domain, int(timeLeft.Hours()))
|
logf("[INFO] acme: [%s] Trying renewal with %d hours remaining", cert.Domain, int(timeLeft.Hours()))
|
||||||
|
|
||||||
// The first step of renewal is to check if we get a renewed cert
|
// The first step of renewal is to check if we get a renewed cert
|
||||||
// directly from the cert URL.
|
// directly from the cert URL.
|
||||||
|
@ -285,7 +294,7 @@ func (c *Client) RenewCertificate(cert CertificateResource, revokeOld bool, bund
|
||||||
// If the server responds with a different certificate we are effectively renewed.
|
// If the server responds with a different certificate we are effectively renewed.
|
||||||
// TODO: Further test if we can actually use the new certificate (Our private key works)
|
// TODO: Further test if we can actually use the new certificate (Our private key works)
|
||||||
if !x509Cert.Equal(serverCert) {
|
if !x509Cert.Equal(serverCert) {
|
||||||
logger().Printf("[%s] The server responded with a renewed certificate.", cert.Domain)
|
logf("[INFO] acme: [%s] Server responded with renewed certificate", cert.Domain)
|
||||||
if revokeOld {
|
if revokeOld {
|
||||||
c.RevokeCertificate(cert.Certificate)
|
c.RevokeCertificate(cert.Certificate)
|
||||||
}
|
}
|
||||||
|
@ -299,7 +308,7 @@ func (c *Client) RenewCertificate(cert CertificateResource, revokeOld bool, bund
|
||||||
issuerCert, err := c.getIssuerCertificate(links["up"])
|
issuerCert, err := c.getIssuerCertificate(links["up"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we fail to aquire the issuer cert, return the issued certificate - do not fail.
|
// If we fail to aquire the issuer cert, return the issued certificate - do not fail.
|
||||||
logger().Printf("[%s] Could not bundle issuer certificate.\n%v", cert.Domain, err)
|
logf("[ERROR] acme: [%s] Could not bundle issuer certificate: %v", cert.Domain, err)
|
||||||
} else {
|
} else {
|
||||||
// Success - append the issuer cert to the issued cert.
|
// Success - append the issuer cert to the issued cert.
|
||||||
issuerCert = pemEncode(derCertificateBytes(issuerCert))
|
issuerCert = pemEncode(derCertificateBytes(issuerCert))
|
||||||
|
@ -340,7 +349,7 @@ func (c *Client) solveChallenges(challenges []*authorizationResource) map[string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
failures[authz.Domain] = fmt.Errorf("Could not determine solvers for %s", authz.Domain)
|
failures[authz.Domain] = fmt.Errorf("acme: Could not determine solvers for %s", authz.Domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +365,7 @@ func (c *Client) chooseSolvers(auth authorization, domain string) map[int]solver
|
||||||
if solver, ok := c.solvers[auth.Challenges[idx].Type]; ok {
|
if solver, ok := c.solvers[auth.Challenges[idx].Type]; ok {
|
||||||
solvers[idx] = solver
|
solvers[idx] = solver
|
||||||
} else {
|
} else {
|
||||||
logger().Printf("Could not find solver for: %s", auth.Challenges[idx].Type)
|
logf("[ERROR] acme: Could not find solver for: %s", auth.Challenges[idx].Type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +401,7 @@ func (c *Client) getChallenges(domains []string) ([]*authorizationResource, map[
|
||||||
|
|
||||||
links := parseLinks(resp.Header["Link"])
|
links := parseLinks(resp.Header["Link"])
|
||||||
if links["next"] == "" {
|
if links["next"] == "" {
|
||||||
logger().Println("The server did not provide enough information to proceed.")
|
logf("[ERROR] acme: Server did not provide next link to proceed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,7 +523,7 @@ func (c *Client) requestCertificate(authz *authorizationResource, result chan Ce
|
||||||
issuerCert, err := c.getIssuerCertificate(links["up"])
|
issuerCert, err := c.getIssuerCertificate(links["up"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we fail to aquire the issuer cert, return the issued certificate - do not fail.
|
// If we fail to aquire the issuer cert, return the issued certificate - do not fail.
|
||||||
logger().Printf("[%s] Could not bundle issuer certificate.\n%v", authz.Domain, err)
|
logf("[WARNING] acme: [%s] Could not bundle issuer certificate: %v", authz.Domain, err)
|
||||||
} else {
|
} else {
|
||||||
// Success - append the issuer cert to the issued cert.
|
// Success - append the issuer cert to the issued cert.
|
||||||
issuerCert = pemEncode(derCertificateBytes(issuerCert))
|
issuerCert = pemEncode(derCertificateBytes(issuerCert))
|
||||||
|
@ -523,7 +532,7 @@ func (c *Client) requestCertificate(authz *authorizationResource, result chan Ce
|
||||||
}
|
}
|
||||||
|
|
||||||
cerRes.Certificate = issuedCert
|
cerRes.Certificate = issuedCert
|
||||||
logger().Printf("[%s] Server responded with a certificate.", authz.Domain)
|
logf("[%s] Server responded with a certificate.", authz.Domain)
|
||||||
result <- cerRes
|
result <- cerRes
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -537,7 +546,7 @@ func (c *Client) requestCertificate(authz *authorizationResource, result chan Ce
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger().Printf("[%s] Server responded with status 202. Respecting retry-after of: %d", authz.Domain, retryAfter)
|
logf("[INFO] acme: [%s] Server responded with status 202; retrying after %ds", authz.Domain, retryAfter)
|
||||||
time.Sleep(time.Duration(retryAfter) * time.Second)
|
time.Sleep(time.Duration(retryAfter) * time.Second)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -557,7 +566,7 @@ func (c *Client) requestCertificate(authz *authorizationResource, result chan Ce
|
||||||
// getIssuerCertificate requests the issuer certificate and caches it for
|
// getIssuerCertificate requests the issuer certificate and caches it for
|
||||||
// subsequent requests.
|
// subsequent requests.
|
||||||
func (c *Client) getIssuerCertificate(url string) ([]byte, error) {
|
func (c *Client) getIssuerCertificate(url string) ([]byte, error) {
|
||||||
logger().Printf("Requesting issuer cert from: %s", url)
|
logf("[INFO] acme: Requesting issuer cert from %s", url)
|
||||||
if c.issuerCert != nil {
|
if c.issuerCert != nil {
|
||||||
return c.issuerCert, nil
|
return c.issuerCert, nil
|
||||||
}
|
}
|
||||||
|
@ -581,18 +590,6 @@ func (c *Client) getIssuerCertificate(url string) ([]byte, error) {
|
||||||
return issuerBytes, err
|
return issuerBytes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func logResponseHeaders(resp *http.Response) {
|
|
||||||
logger().Println(resp.Status)
|
|
||||||
for k, v := range resp.Header {
|
|
||||||
logger().Printf("-- %s: %s", k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func logResponseBody(resp *http.Response) {
|
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
logger().Printf("Returned json data: \n%s", body)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseLinks(links []string) map[string]string {
|
func parseLinks(links []string) map[string]string {
|
||||||
aBrkt := regexp.MustCompile("[<>]")
|
aBrkt := regexp.MustCompile("[<>]")
|
||||||
slver := regexp.MustCompile("(.+) *= *\"(.+)\"")
|
slver := regexp.MustCompile("(.+) *= *\"(.+)\"")
|
||||||
|
|
|
@ -44,7 +44,7 @@ func TestNewClient(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected, actual := 1, len(client.solvers); actual != expected {
|
if expected, actual := 1, len(client.solvers); actual != expected {
|
||||||
t.Fatal("Expected %d solver(s), got %d", expected, actual)
|
t.Fatalf("Expected %d solver(s), got %d", expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
simphttp, ok := client.solvers["simpleHttp"].(*simpleHTTPChallenge)
|
simphttp, ok := client.solvers["simpleHttp"].(*simpleHTTPChallenge)
|
||||||
|
|
|
@ -18,7 +18,7 @@ type RemoteError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e RemoteError) Error() string {
|
func (e RemoteError) Error() string {
|
||||||
return fmt.Sprintf("[%d] Type: %s Detail: %s", e.StatusCode, e.Type, e.Detail)
|
return fmt.Sprintf("acme: Error %d - %s - %s", e.StatusCode, e.Type, e.Detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOSError represents the error which is returned if the user needs to
|
// TOSError represents the error which is returned if the user needs to
|
||||||
|
|
|
@ -27,7 +27,7 @@ type simpleHTTPChallenge struct {
|
||||||
|
|
||||||
func (s *simpleHTTPChallenge) Solve(chlng challenge, domain string) error {
|
func (s *simpleHTTPChallenge) Solve(chlng challenge, domain string) error {
|
||||||
|
|
||||||
logger().Print("Trying to solve SimpleHTTP")
|
logf("Trying to solve SimpleHTTP")
|
||||||
|
|
||||||
// Generate random string for the path. The acme server will
|
// Generate random string for the path. The acme server will
|
||||||
// access this path on the server in order to validate the request
|
// access this path on the server in order to validate the request
|
||||||
|
@ -68,7 +68,7 @@ Loop:
|
||||||
if OnSimpleHTTPEnd != nil {
|
if OnSimpleHTTPEnd != nil {
|
||||||
OnSimpleHTTPEnd(true)
|
OnSimpleHTTPEnd(true)
|
||||||
}
|
}
|
||||||
logger().Print("The server validated our request")
|
logf("The server validated our request")
|
||||||
break Loop
|
break Loop
|
||||||
case "pending":
|
case "pending":
|
||||||
break
|
break
|
||||||
|
@ -148,9 +148,9 @@ func (s *simpleHTTPChallenge) startHTTPSServer(domain string, token string) (net
|
||||||
if strings.HasPrefix(r.Host, domain) && r.Method == "GET" {
|
if strings.HasPrefix(r.Host, domain) && r.Method == "GET" {
|
||||||
w.Header().Add("Content-Type", "application/jose+json")
|
w.Header().Add("Content-Type", "application/jose+json")
|
||||||
w.Write([]byte(signedCompact))
|
w.Write([]byte(signedCompact))
|
||||||
logger().Print("Served JWS payload...")
|
logf("Served JWS payload...")
|
||||||
} else {
|
} else {
|
||||||
logger().Printf("Received request for domain %s with method %s", r.Host, r.Method)
|
logf("Received request for domain %s with method %s", r.Host, r.Method)
|
||||||
w.Write([]byte("TEST"))
|
w.Write([]byte("TEST"))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -138,7 +138,7 @@ func TestSimpleHTTPServerError(t *testing.T) {
|
||||||
if err := solver.Solve(clientChallenge, "127.0.0.1"); err == nil {
|
if err := solver.Solve(clientChallenge, "127.0.0.1"); err == nil {
|
||||||
t.Error("UNEXPECTED: Expected Solve to return an error but the error was nil.")
|
t.Error("UNEXPECTED: Expected Solve to return an error but the error was nil.")
|
||||||
} else {
|
} else {
|
||||||
expectedError := "[500] Type: urn:acme:error:unauthorized Detail: Error creating new authz :: Syntax error"
|
expectedError := "acme: Error 500 - urn:acme:error:unauthorized - Error creating new authz :: Syntax error"
|
||||||
if err.Error() != expectedError {
|
if err.Error() != expectedError {
|
||||||
t.Errorf("Expected error |%s| but instead got |%s|", expectedError, err.Error())
|
t.Errorf("Expected error |%s| but instead got |%s|", expectedError, err.Error())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue