2016-05-27 09:13:34 +00:00
package acme
import (
2017-06-19 11:22:41 +00:00
"crypto/tls"
2016-10-14 00:33:01 +00:00
"encoding/base64"
"net/http"
"net/http/httptest"
2016-05-27 09:13:34 +00:00
"reflect"
2016-06-20 11:55:50 +00:00
"sync"
2016-05-27 09:13:34 +00:00
"testing"
2016-12-14 17:10:10 +00:00
"time"
2016-12-30 08:21:13 +00:00
2017-11-09 11:16:03 +00:00
"github.com/containous/traefik/tls/generate"
2017-06-19 11:22:41 +00:00
"github.com/stretchr/testify/assert"
2016-12-30 08:21:13 +00:00
"github.com/xenolf/lego/acme"
2016-05-27 09:13:34 +00:00
)
func TestDomainsSet ( t * testing . T ) {
checkMap := map [ string ] Domains {
"" : { } ,
"foo.com" : { Domain { Main : "foo.com" , SANs : [ ] string { } } } ,
"foo.com,bar.net" : { Domain { Main : "foo.com" , SANs : [ ] string { "bar.net" } } } ,
"foo.com,bar1.net,bar2.net,bar3.net" : { Domain { Main : "foo.com" , SANs : [ ] string { "bar1.net" , "bar2.net" , "bar3.net" } } } ,
}
for in , check := range checkMap {
ds := Domains { }
ds . Set ( in )
if ! reflect . DeepEqual ( check , ds ) {
2016-06-20 11:55:50 +00:00
t . Errorf ( "Expected %+v\nGot %+v" , check , ds )
2016-05-27 09:13:34 +00:00
}
}
}
func TestDomainsSetAppend ( t * testing . T ) {
inSlice := [ ] string {
"" ,
"foo1.com" ,
"foo2.com,bar.net" ,
"foo3.com,bar1.net,bar2.net,bar3.net" ,
}
checkSlice := [ ] Domains {
{ } ,
{
Domain {
Main : "foo1.com" ,
SANs : [ ] string { } } } ,
{
Domain {
Main : "foo1.com" ,
SANs : [ ] string { } } ,
Domain {
Main : "foo2.com" ,
SANs : [ ] string { "bar.net" } } } ,
{
Domain {
Main : "foo1.com" ,
SANs : [ ] string { } } ,
Domain {
Main : "foo2.com" ,
SANs : [ ] string { "bar.net" } } ,
Domain { Main : "foo3.com" ,
SANs : [ ] string { "bar1.net" , "bar2.net" , "bar3.net" } } } ,
}
ds := Domains { }
for i , in := range inSlice {
ds . Set ( in )
if ! reflect . DeepEqual ( checkSlice [ i ] , ds ) {
2016-06-20 11:55:50 +00:00
t . Errorf ( "Expected %s %+v\nGot %+v" , in , checkSlice [ i ] , ds )
2016-05-27 09:13:34 +00:00
}
}
}
2016-06-20 11:55:50 +00:00
func TestCertificatesRenew ( t * testing . T ) {
2017-11-09 11:16:03 +00:00
foo1Cert , foo1Key , _ := generate . KeyPair ( "foo1.com" , time . Now ( ) )
foo2Cert , foo2Key , _ := generate . KeyPair ( "foo2.com" , time . Now ( ) )
2016-06-20 11:55:50 +00:00
domainsCertificates := DomainsCertificates {
2016-09-23 16:27:01 +00:00
lock : sync . RWMutex { } ,
2016-06-20 11:55:50 +00:00
Certs : [ ] * DomainsCertificate {
{
Domains : Domain {
Main : "foo1.com" ,
SANs : [ ] string { } } ,
Certificate : & Certificate {
Domain : "foo1.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
2016-12-14 17:10:10 +00:00
PrivateKey : foo1Key ,
Certificate : foo1Cert ,
2016-06-20 11:55:50 +00:00
} ,
} ,
{
Domains : Domain {
Main : "foo2.com" ,
SANs : [ ] string { } } ,
Certificate : & Certificate {
Domain : "foo2.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
2016-12-14 17:10:10 +00:00
PrivateKey : foo2Key ,
Certificate : foo2Cert ,
2016-06-20 11:55:50 +00:00
} ,
} ,
} ,
}
2017-11-09 11:16:03 +00:00
foo1Cert , foo1Key , _ = generate . KeyPair ( "foo1.com" , time . Now ( ) )
2016-06-20 11:55:50 +00:00
newCertificate := & Certificate {
Domain : "foo1.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
2016-12-14 17:10:10 +00:00
PrivateKey : foo1Key ,
Certificate : foo1Cert ,
2016-06-20 11:55:50 +00:00
}
err := domainsCertificates . renewCertificates (
newCertificate ,
Domain {
Main : "foo1.com" ,
SANs : [ ] string { } } )
if err != nil {
t . Errorf ( "Error in renewCertificates :%v" , err )
}
if len ( domainsCertificates . Certs ) != 2 {
t . Errorf ( "Expected domainsCertificates length %d %+v\nGot %+v" , 2 , domainsCertificates . Certs , len ( domainsCertificates . Certs ) )
}
if ! reflect . DeepEqual ( domainsCertificates . Certs [ 0 ] . Certificate , newCertificate ) {
t . Errorf ( "Expected new certificate %+v \nGot %+v" , newCertificate , domainsCertificates . Certs [ 0 ] . Certificate )
}
}
2016-10-14 00:33:01 +00:00
2016-12-14 17:10:10 +00:00
func TestRemoveDuplicates ( t * testing . T ) {
now := time . Now ( )
2017-11-09 11:16:03 +00:00
fooCert , fooKey , _ := generate . KeyPair ( "foo.com" , now )
foo24Cert , foo24Key , _ := generate . KeyPair ( "foo.com" , now . Add ( 24 * time . Hour ) )
foo48Cert , foo48Key , _ := generate . KeyPair ( "foo.com" , now . Add ( 48 * time . Hour ) )
barCert , barKey , _ := generate . KeyPair ( "bar.com" , now )
2016-12-14 17:10:10 +00:00
domainsCertificates := DomainsCertificates {
lock : sync . RWMutex { } ,
Certs : [ ] * DomainsCertificate {
{
Domains : Domain {
Main : "foo.com" ,
SANs : [ ] string { } } ,
Certificate : & Certificate {
Domain : "foo.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
PrivateKey : foo24Key ,
Certificate : foo24Cert ,
} ,
} ,
{
Domains : Domain {
Main : "foo.com" ,
SANs : [ ] string { } } ,
Certificate : & Certificate {
Domain : "foo.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
PrivateKey : foo48Key ,
Certificate : foo48Cert ,
} ,
} ,
{
Domains : Domain {
Main : "foo.com" ,
SANs : [ ] string { } } ,
Certificate : & Certificate {
Domain : "foo.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
PrivateKey : fooKey ,
Certificate : fooCert ,
} ,
} ,
{
Domains : Domain {
Main : "bar.com" ,
SANs : [ ] string { } } ,
Certificate : & Certificate {
Domain : "bar.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
PrivateKey : barKey ,
Certificate : barCert ,
} ,
} ,
{
Domains : Domain {
Main : "foo.com" ,
SANs : [ ] string { } } ,
Certificate : & Certificate {
Domain : "foo.com" ,
CertURL : "url" ,
CertStableURL : "url" ,
PrivateKey : foo48Key ,
Certificate : foo48Cert ,
} ,
} ,
} ,
}
domainsCertificates . Init ( )
if len ( domainsCertificates . Certs ) != 2 {
t . Errorf ( "Expected domainsCertificates length %d %+v\nGot %+v" , 2 , domainsCertificates . Certs , len ( domainsCertificates . Certs ) )
}
for _ , cert := range domainsCertificates . Certs {
switch cert . Domains . Main {
case "bar.com" :
continue
case "foo.com" :
if ! cert . tlsCert . Leaf . NotAfter . Equal ( now . Add ( 48 * time . Hour ) . Truncate ( 1 * time . Second ) ) {
t . Errorf ( "Bad expiration %s date for domain %+v, now %s" , cert . tlsCert . Leaf . NotAfter . String ( ) , cert , now . Add ( 48 * time . Hour ) . Truncate ( 1 * time . Second ) . String ( ) )
}
default :
2017-02-02 20:07:44 +00:00
t . Errorf ( "Unknown domain %+v" , cert )
2016-12-14 17:10:10 +00:00
}
}
}
2016-10-14 00:33:01 +00:00
func TestNoPreCheckOverride ( t * testing . T ) {
acme . PreCheckDNS = nil // Irreversable - but not expecting real calls into this during testing process
err := dnsOverrideDelay ( 0 )
if err != nil {
t . Errorf ( "Error in dnsOverrideDelay :%v" , err )
}
if acme . PreCheckDNS != nil {
2017-05-26 15:03:14 +00:00
t . Error ( "Unexpected change to acme.PreCheckDNS when leaving DNS verification as is." )
2016-10-14 00:33:01 +00:00
}
}
func TestSillyPreCheckOverride ( t * testing . T ) {
err := dnsOverrideDelay ( - 5 )
if err == nil {
2017-05-26 15:03:14 +00:00
t . Error ( "Missing expected error in dnsOverrideDelay!" )
2016-10-14 00:33:01 +00:00
}
}
func TestPreCheckOverride ( t * testing . T ) {
acme . PreCheckDNS = nil // Irreversable - but not expecting real calls into this during testing process
err := dnsOverrideDelay ( 5 )
if err != nil {
t . Errorf ( "Error in dnsOverrideDelay :%v" , err )
}
if acme . PreCheckDNS == nil {
2017-05-26 15:03:14 +00:00
t . Error ( "No change to acme.PreCheckDNS when meant to be adding enforcing override function." )
2016-10-14 00:33:01 +00:00
}
}
func TestAcmeClientCreation ( t * testing . T ) {
acme . PreCheckDNS = nil // Irreversable - but not expecting real calls into this during testing process
// Lengthy setup to avoid external web requests - oh for easier golang testing!
account := & Account { Email : "f@f" }
account . PrivateKey , _ = base64 . StdEncoding . DecodeString ( `
MIIBPAIBAAJBAMp2Ni92FfEur + CAvFkgC12LT4l9D53ApbBpDaXaJkzzks + KsLw9zyAxvlrfAyTCQ
7 tDnEnIltAXyQ0uOFUUdcMCAwEAAQJAK1FbipATZcT9cGVa5x7KD7usytftLW14heQUPXYNV80r / 3
lmnpvjL06dffRpwkYeN8DATQF / QOcy3NNNGDw / 4 QIhAPAKmiZFxA / qmRXsuU8Zhlzf16WrNZ68K64
asn / h3qZrAiEA1 + wFR3WXCPIolOvd7AHjfgcTKQNkoMPywU4FYUNQ1AkCIQDv8yk0qPjckD6HVCPJ
llJh9MC0svjevGtNlxJoE3lmEQIhAKXy1wfZ32 / XtcrnENPvi6lzxI0T94X7s5pP3aCoPPoJAiEAl
cijFkALeQp / qyeXdFld2v9gUN3eCgljgcl0QweRoIc = -- - ` )
ts := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . Write ( [ ] byte ( ` {
"new-authz" : "https://foo/acme/new-authz" ,
"new-cert" : "https://foo/acme/new-cert" ,
"new-reg" : "https://foo/acme/new-reg" ,
"revoke-cert" : "https://foo/acme/revoke-cert"
} ` ) )
} ) )
defer ts . Close ( )
2018-01-15 15:04:05 +00:00
a := ACME { DNSChallenge : & DNSChallenge { Provider : "manual" , DelayBeforeCheck : 10 } , CAServer : ts . URL }
2016-10-14 00:33:01 +00:00
client , err := a . buildACMEClient ( account )
if err != nil {
t . Errorf ( "Error in buildACMEClient: %v" , err )
}
if client == nil {
2017-05-26 15:03:14 +00:00
t . Error ( "No client from buildACMEClient!" )
2016-10-14 00:33:01 +00:00
}
if acme . PreCheckDNS == nil {
2017-05-26 15:03:14 +00:00
t . Error ( "No change to acme.PreCheckDNS when meant to be adding enforcing override function." )
2016-10-14 00:33:01 +00:00
}
}
2017-06-19 11:22:41 +00:00
2018-02-26 10:38:03 +00:00
func TestAcme_getUncheckedCertificates ( t * testing . T ) {
2017-06-19 11:22:41 +00:00
mm := make ( map [ string ] * tls . Certificate )
mm [ "*.containo.us" ] = & tls . Certificate { }
mm [ "traefik.acme.io" ] = & tls . Certificate { }
a := ACME { TLSConfig : & tls . Config { NameToCertificate : mm } }
domains := [ ] string { "traefik.containo.us" , "trae.containo.us" }
2018-02-26 10:38:03 +00:00
uncheckedDomains := a . getUncheckedDomains ( domains , nil )
assert . Empty ( t , uncheckedDomains )
2017-06-19 11:22:41 +00:00
domains = [ ] string { "traefik.acme.io" , "trae.acme.io" }
2018-02-26 10:38:03 +00:00
uncheckedDomains = a . getUncheckedDomains ( domains , nil )
assert . Len ( t , uncheckedDomains , 1 )
domainsCertificates := DomainsCertificates { Certs : [ ] * DomainsCertificate {
{
tlsCert : & tls . Certificate { } ,
Domains : Domain {
Main : "*.acme.wtf" ,
SANs : [ ] string { "trae.acme.io" } ,
} ,
} ,
} }
account := Account { DomainsCertificate : domainsCertificates }
uncheckedDomains = a . getUncheckedDomains ( domains , & account )
assert . Empty ( t , uncheckedDomains )
}
func TestAcme_getProvidedCertificate ( t * testing . T ) {
mm := make ( map [ string ] * tls . Certificate )
mm [ "*.containo.us" ] = & tls . Certificate { }
mm [ "traefik.acme.io" ] = & tls . Certificate { }
a := ACME { TLSConfig : & tls . Config { NameToCertificate : mm } }
domain := "traefik.containo.us"
certificate := a . getProvidedCertificate ( domain )
assert . NotNil ( t , certificate )
domain = "trae.acme.io"
certificate = a . getProvidedCertificate ( domain )
2017-06-19 11:22:41 +00:00
assert . Nil ( t , certificate )
}