Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
42ac2d2d
Commit
42ac2d2d
authored
Oct 18, 2015
by
Matthew Holt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
letsencrypt: More tests, tests for user.go & slight refactoring
parent
d7641118
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
238 additions
and
16 deletions
+238
-16
config/letsencrypt/crypto_test.go
config/letsencrypt/crypto_test.go
+16
-5
config/letsencrypt/letsencrypt.go
config/letsencrypt/letsencrypt.go
+13
-8
config/letsencrypt/user.go
config/letsencrypt/user.go
+17
-3
config/letsencrypt/user_test.go
config/letsencrypt/user_test.go
+192
-0
No files found.
config/letsencrypt/crypto_test.go
View file @
42ac2d2d
...
...
@@ -5,20 +5,22 @@ import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"
"testing"
)
func
init
()
{
rsaKeySizeToUse
=
128
// makes tests faster
}
func
TestSaveAndLoadRSAPrivateKey
(
t
*
testing
.
T
)
{
keyFile
:=
"test.key"
defer
os
.
Remove
(
keyFile
)
privateKey
,
err
:=
rsa
.
GenerateKey
(
rand
.
Reader
,
256
)
// small key size is OK for testing
privateKey
,
err
:=
rsa
.
GenerateKey
(
rand
.
Reader
,
128
)
// small key size is OK for testing
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
privateKeyPEM
:=
pem
.
Block
{
Type
:
"RSA PRIVATE KEY"
,
Bytes
:
x509
.
MarshalPKCS1PrivateKey
(
privateKey
)}
// test save
err
=
saveRSAPrivateKey
(
privateKey
,
keyFile
)
...
...
@@ -31,10 +33,19 @@ func TestSaveAndLoadRSAPrivateKey(t *testing.T) {
if
err
!=
nil
{
t
.
Error
(
"error loading private key:"
,
err
)
}
loadedKeyPEM
:=
pem
.
Block
{
Type
:
"RSA PRIVATE KEY"
,
Bytes
:
x509
.
MarshalPKCS1PrivateKey
(
loadedKey
)}
// very loaded key is correct
if
!
bytes
.
Equal
(
loadedKeyPEM
.
Bytes
,
privateKeyPEM
.
Bytes
)
{
if
!
rsaPrivateKeysSame
(
privateKey
,
loadedKey
)
{
t
.
Error
(
"Expected key bytes to be the same, but they weren't"
)
}
}
// rsaPrivateKeyBytes returns the bytes of DER-encoded key.
func
rsaPrivateKeyBytes
(
key
*
rsa
.
PrivateKey
)
[]
byte
{
return
x509
.
MarshalPKCS1PrivateKey
(
key
)
}
// rsaPrivateKeysSame compares the bytes of a and b and returns true if they are the same.
func
rsaPrivateKeysSame
(
a
,
b
*
rsa
.
PrivateKey
)
bool
{
return
bytes
.
Equal
(
rsaPrivateKeyBytes
(
a
),
rsaPrivateKeyBytes
(
b
))
}
config/letsencrypt/letsencrypt.go
View file @
42ac2d2d
// Package letsencrypt integrates Let's Encrypt with Caddy with first-class support.
// It is designed to configure sites for HTTPS by default.
// Package letsencrypt integrates Let's Encrypt functionality into Caddy
// with first-class support for creating and renewing certificates
// automatically. It is designed to configure sites for HTTPS by default.
package
letsencrypt
import
(
...
...
@@ -126,7 +127,7 @@ func newClient(leEmail string) (*acme.Client, error) {
}
// The client facilitates our communication with the CA server.
client
:=
acme
.
NewClient
(
caURL
,
&
leUser
,
rsaKeySize
,
exposePort
,
true
)
// TODO: Dev mode is enabled
client
:=
acme
.
NewClient
(
caURL
,
&
leUser
,
rsaKeySize
ToUse
,
exposePort
,
true
)
// TODO: Dev mode is enabled
// If not registered, the user must register an account with the CA
// and agree to terms
...
...
@@ -268,9 +269,6 @@ var (
// Some essential values related to the Let's Encrypt process
const
(
// Size of RSA keys in bits
rsaKeySize
=
2048
// The base URL to the Let's Encrypt CA
caURL
=
"http://192.168.99.100:4000"
...
...
@@ -278,10 +276,10 @@ const (
exposePort
=
"5001"
)
// KeySize represents the length of a key in bits
// KeySize represents the length of a key in bits
.
type
KeySize
int
// Key sizes
// Key sizes
are used to determine the strength of a key.
const
(
ECC_224
KeySize
=
224
ECC_256
=
256
...
...
@@ -289,6 +287,13 @@ const (
RSA_4096
=
4096
)
// rsaKeySizeToUse is the size to use for new RSA keys.
// This shouldn't need to change except for in tests;
// the size can be drastically reduced for speed.
var
rsaKeySizeToUse
=
RSA_2048
// CertificateMeta is a container type used to write out a file
// with information about a certificate.
type
CertificateMeta
struct
{
Domain
,
URL
string
}
config/letsencrypt/user.go
View file @
42ac2d2d
...
...
@@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
...
...
@@ -15,6 +16,7 @@ import (
"github.com/xenolf/lego/acme"
)
// User represents a Let's Encrypt user account.
type
User
struct
{
Email
string
Registration
*
acme
.
RegistrationResource
...
...
@@ -22,18 +24,25 @@ type User struct {
key
*
rsa
.
PrivateKey
}
// GetEmail gets u's email.
func
(
u
User
)
GetEmail
()
string
{
return
u
.
Email
}
// GetRegistration gets u's registration resource.
func
(
u
User
)
GetRegistration
()
*
acme
.
RegistrationResource
{
return
u
.
Registration
}
// GetPrivateKey gets u's private key.
func
(
u
User
)
GetPrivateKey
()
*
rsa
.
PrivateKey
{
return
u
.
key
}
// getUser loads the user with the given email from disk.
// If the user does not exist, it will create a new one.
// If the user does not exist, it will create a new one,
// but it does NOT save new users to the disk or register
// them via ACME.
func
getUser
(
email
string
)
(
User
,
error
)
{
var
user
User
...
...
@@ -95,7 +104,7 @@ func saveUser(user User) error {
// instead.
func
newUser
(
email
string
)
(
User
,
error
)
{
user
:=
User
{
Email
:
email
}
privateKey
,
err
:=
rsa
.
GenerateKey
(
rand
.
Reader
,
rsaKeySize
)
privateKey
,
err
:=
rsa
.
GenerateKey
(
rand
.
Reader
,
rsaKeySize
ToUse
)
if
err
!=
nil
{
return
user
,
errors
.
New
(
"error generating private key: "
+
err
.
Error
())
}
...
...
@@ -134,7 +143,8 @@ func getEmail(cfg server.Config) string {
}
if
leEmail
==
""
{
// Alas, we must bother the user and ask for an email address
reader
:=
bufio
.
NewReader
(
os
.
Stdin
)
// TODO/BUG: This doesn't work when Caddyfile is piped into caddy
reader
:=
bufio
.
NewReader
(
stdin
)
fmt
.
Print
(
"Email address: "
)
// TODO: More explanation probably, and show ToS?
var
err
error
leEmail
,
err
=
reader
.
ReadString
(
'\n'
)
...
...
@@ -145,3 +155,7 @@ func getEmail(cfg server.Config) string {
}
return
strings
.
TrimSpace
(
leEmail
)
}
// stdin is used to read the user's input if prompted;
// this is changed by tests during tests.
var
stdin
=
io
.
ReadWriter
(
os
.
Stdin
)
config/letsencrypt/user_test.go
0 → 100644
View file @
42ac2d2d
package
letsencrypt
import
(
"bytes"
"crypto/rand"
"crypto/rsa"
"io"
"os"
"strings"
"testing"
"time"
"github.com/mholt/caddy/server"
"github.com/xenolf/lego/acme"
)
func
TestUser
(
t
*
testing
.
T
)
{
privateKey
,
err
:=
rsa
.
GenerateKey
(
rand
.
Reader
,
128
)
if
err
!=
nil
{
t
.
Fatalf
(
"Could not generate test private key: %v"
,
err
)
}
u
:=
User
{
Email
:
"me@mine.com"
,
Registration
:
new
(
acme
.
RegistrationResource
),
key
:
privateKey
,
}
if
expected
,
actual
:=
"me@mine.com"
,
u
.
GetEmail
();
actual
!=
expected
{
t
.
Errorf
(
"Expected email '%s' but got '%s'"
,
expected
,
actual
)
}
if
u
.
GetRegistration
()
==
nil
{
t
.
Error
(
"Expected a registration resource, but got nil"
)
}
if
expected
,
actual
:=
privateKey
,
u
.
GetPrivateKey
();
actual
!=
expected
{
t
.
Errorf
(
"Expected the private key at address %p but got one at %p instead "
,
expected
,
actual
)
}
}
func
TestNewUser
(
t
*
testing
.
T
)
{
email
:=
"me@foobar.com"
user
,
err
:=
newUser
(
email
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error creating user: %v"
,
err
)
}
if
user
.
key
==
nil
{
t
.
Error
(
"Private key is nil"
)
}
if
user
.
Email
!=
email
{
t
.
Errorf
(
"Expected email to be %s, but was %s"
,
email
,
user
.
Email
)
}
if
user
.
Registration
!=
nil
{
t
.
Error
(
"New user already has a registration resource; it shouldn't"
)
}
}
func
TestSaveUser
(
t
*
testing
.
T
)
{
storage
=
Storage
(
"./testdata"
)
defer
os
.
RemoveAll
(
string
(
storage
))
email
:=
"me@foobar.com"
user
,
err
:=
newUser
(
email
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error creating user: %v"
,
err
)
}
err
=
saveUser
(
user
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error saving user: %v"
,
err
)
}
_
,
err
=
os
.
Stat
(
storage
.
UserRegFile
(
email
))
if
err
!=
nil
{
t
.
Errorf
(
"Cannot access user registration file, error: %v"
,
err
)
}
_
,
err
=
os
.
Stat
(
storage
.
UserKeyFile
(
email
))
if
err
!=
nil
{
t
.
Errorf
(
"Cannot access user private key file, error: %v"
,
err
)
}
}
func
TestGetUserDoesNotAlreadyExist
(
t
*
testing
.
T
)
{
storage
=
Storage
(
"./testdata"
)
defer
os
.
RemoveAll
(
string
(
storage
))
user
,
err
:=
getUser
(
"user_does_not_exist@foobar.com"
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error getting user: %v"
,
err
)
}
if
user
.
key
==
nil
{
t
.
Error
(
"Expected user to have a private key, but it was nil"
)
}
}
func
TestGetUserAlreadyExists
(
t
*
testing
.
T
)
{
storage
=
Storage
(
"./testdata"
)
defer
os
.
RemoveAll
(
string
(
storage
))
email
:=
"me@foobar.com"
// Set up test
user
,
err
:=
newUser
(
email
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error creating user: %v"
,
err
)
}
err
=
saveUser
(
user
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error saving user: %v"
,
err
)
}
// Expect to load user from disk
user2
,
err
:=
getUser
(
email
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error getting user: %v"
,
err
)
}
// Assert keys are the same
if
!
rsaPrivateKeysSame
(
user
.
key
,
user2
.
key
)
{
t
.
Error
(
"Expected private key to be the same after loading, but it wasn't"
)
}
// Assert emails are the same
if
user
.
Email
!=
user2
.
Email
{
t
.
Errorf
(
"Expected emails to be equal, but was '%s' before and '%s' after loading"
,
user
.
Email
,
user2
.
Email
)
}
}
func
TestGetEmail
(
t
*
testing
.
T
)
{
storage
=
Storage
(
"./testdata"
)
defer
os
.
RemoveAll
(
string
(
storage
))
DefaultEmail
=
"test2@foo.com"
// Test1: Use email in config
config
:=
server
.
Config
{
TLS
:
server
.
TLSConfig
{
LetsEncryptEmail
:
"test1@foo.com"
,
},
}
actual
:=
getEmail
(
config
)
if
actual
!=
"test1@foo.com"
{
t
.
Errorf
(
"Did not get correct email from config; expected '%s' but got '%s'"
,
"test1@foo.com"
,
actual
)
}
// Test2: Use default email from flag (or user previously typing it)
actual
=
getEmail
(
server
.
Config
{})
if
actual
!=
DefaultEmail
{
t
.
Errorf
(
"Did not get correct email from config; expected '%s' but got '%s'"
,
DefaultEmail
,
actual
)
}
// Test3: Get input from user
DefaultEmail
=
""
stdin
=
new
(
bytes
.
Buffer
)
_
,
err
:=
io
.
Copy
(
stdin
,
strings
.
NewReader
(
"test3@foo.com
\n
"
))
if
err
!=
nil
{
t
.
Fatalf
(
"Could not simulate user input, error: %v"
,
err
)
}
actual
=
getEmail
(
server
.
Config
{})
if
actual
!=
"test3@foo.com"
{
t
.
Errorf
(
"Did not get correct email from user input prompt; expected '%s' but got '%s'"
,
"test3@foo.com"
,
actual
)
}
// Test4: Get most recent email from before
DefaultEmail
=
""
for
i
,
eml
:=
range
[]
string
{
"test4-3@foo.com"
,
"test4-2@foo.com"
,
"test4-1@foo.com"
,
}
{
u
,
err
:=
newUser
(
eml
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error creating user %d: %v"
,
i
,
err
)
}
err
=
saveUser
(
u
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error saving user %d: %v"
,
i
,
err
)
}
// Change modified time so they're all different, so the test becomes deterministic
f
,
err
:=
os
.
Stat
(
storage
.
User
(
eml
))
if
err
!=
nil
{
t
.
Fatalf
(
"Could not access user folder for '%s': %v"
,
eml
,
err
)
}
chTime
:=
f
.
ModTime
()
.
Add
(
-
(
time
.
Duration
(
i
)
*
time
.
Second
))
if
err
:=
os
.
Chtimes
(
storage
.
User
(
eml
),
chTime
,
chTime
);
err
!=
nil
{
t
.
Fatalf
(
"Could not change user folder mod time for '%s': %v"
,
eml
,
err
)
}
}
actual
=
getEmail
(
server
.
Config
{})
if
actual
!=
"test4-3@foo.com"
{
t
.
Errorf
(
"Did not get correct email from storage; expected '%s' but got '%s'"
,
"test4-3@foo.com"
,
actual
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment