2015-04-24 04:46:21 +00:00
|
|
|
package cert
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/tls"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"testing"
|
2015-04-24 19:58:39 +00:00
|
|
|
"time"
|
2015-04-24 04:46:21 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/vault/logical"
|
|
|
|
logicaltest "github.com/hashicorp/vault/logical/testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Test a client trusted by a CA
|
|
|
|
func TestBackend_basic_CA(t *testing.T) {
|
|
|
|
connState := testConnState(t, "../../../test/key/ourdomain.cer",
|
|
|
|
"../../../test/key/ourdomain.key")
|
|
|
|
ca, err := ioutil.ReadFile("../../../test/ca/root.cer")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
|
|
|
Backend: Backend(),
|
|
|
|
Steps: []logicaltest.TestStep{
|
|
|
|
testAccStepCert(t, "web", ca, "foo"),
|
|
|
|
testAccStepLogin(t, connState),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test a self-signed client that is trusted
|
|
|
|
func TestBackend_basic_singleCert(t *testing.T) {
|
|
|
|
connState := testConnState(t, "../../../test/unsigned/cert.pem",
|
|
|
|
"../../../test/unsigned/key.pem")
|
|
|
|
ca, err := ioutil.ReadFile("../../../test/unsigned/cert.pem")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
|
|
|
Backend: Backend(),
|
|
|
|
Steps: []logicaltest.TestStep{
|
|
|
|
testAccStepCert(t, "web", ca, "foo"),
|
|
|
|
testAccStepLogin(t, connState),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test an untrusted self-signed client
|
|
|
|
func TestBackend_untrusted(t *testing.T) {
|
|
|
|
connState := testConnState(t, "../../../test/unsigned/cert.pem",
|
|
|
|
"../../../test/unsigned/key.pem")
|
|
|
|
logicaltest.Test(t, logicaltest.TestCase{
|
|
|
|
Backend: Backend(),
|
|
|
|
Steps: []logicaltest.TestStep{
|
|
|
|
testAccStepLoginInvalid(t, connState),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepLogin(t *testing.T, connState tls.ConnectionState) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
|
|
|
Operation: logical.WriteOperation,
|
|
|
|
Path: "login",
|
|
|
|
Unauthenticated: true,
|
|
|
|
ConnState: &connState,
|
2015-04-24 19:58:39 +00:00
|
|
|
Check: func(resp *logical.Response) error {
|
|
|
|
if resp.Auth.Lease != 1000*time.Second {
|
|
|
|
t.Fatalf("bad lease length: %#v", resp.Auth)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn := logicaltest.TestCheckAuth([]string{"foo"})
|
|
|
|
return fn(resp)
|
|
|
|
},
|
2015-04-24 04:46:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepLoginInvalid(t *testing.T, connState tls.ConnectionState) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
|
|
|
Operation: logical.WriteOperation,
|
|
|
|
Path: "login",
|
|
|
|
Unauthenticated: true,
|
|
|
|
ConnState: &connState,
|
|
|
|
Check: func(resp *logical.Response) error {
|
2015-04-24 17:39:44 +00:00
|
|
|
if resp.Auth != nil {
|
|
|
|
return fmt.Errorf("should not be authorized: %#v", resp)
|
2015-04-24 04:46:21 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
2015-04-24 17:39:44 +00:00
|
|
|
ErrorOk: true,
|
2015-04-24 04:46:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAccStepCert(
|
|
|
|
t *testing.T, name string, cert []byte, policies string) logicaltest.TestStep {
|
|
|
|
return logicaltest.TestStep{
|
|
|
|
Operation: logical.WriteOperation,
|
2015-04-24 17:31:57 +00:00
|
|
|
Path: "certs/" + name,
|
2015-04-24 04:46:21 +00:00
|
|
|
Data: map[string]interface{}{
|
|
|
|
"certificate": string(cert),
|
2015-04-24 17:31:57 +00:00
|
|
|
"policies": policies,
|
2015-04-24 04:46:21 +00:00
|
|
|
"display_name": name,
|
2015-04-24 19:58:39 +00:00
|
|
|
"lease": 1000,
|
2015-04-24 04:46:21 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testConnState(t *testing.T, certPath, keyPath string) tls.ConnectionState {
|
|
|
|
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
conf := &tls.Config{
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
ClientAuth: tls.RequestClientCert,
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
}
|
|
|
|
list, err := tls.Listen("tcp", "127.0.0.1:0", conf)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
defer list.Close()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
addr := list.Addr().String()
|
|
|
|
conn, err := tls.Dial("tcp", addr, conf)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
|
|
|
|
// Write ping
|
|
|
|
conn.Write([]byte("ping"))
|
|
|
|
}()
|
|
|
|
|
|
|
|
serverConn, err := list.Accept()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
defer serverConn.Close()
|
|
|
|
|
|
|
|
// Read the pign
|
|
|
|
buf := make([]byte, 4)
|
|
|
|
serverConn.Read(buf)
|
|
|
|
|
|
|
|
// Grab the current state
|
|
|
|
connState := serverConn.(*tls.Conn).ConnectionState()
|
|
|
|
return connState
|
|
|
|
}
|