vendor: Update vendoring for the exec client and server implementations
Signed-off-by: Jacek J. Łakis <jacek.lakis@intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
d25b88583f
commit
bf51655a7b
2124 changed files with 809703 additions and 5 deletions
2
vendor/github.com/coreos/go-oidc/key/doc.go
generated
vendored
Normal file
2
vendor/github.com/coreos/go-oidc/key/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
// Package key is DEPRECATED. Use github.com/coreos/go-oidc instead.
|
||||
package key
|
153
vendor/github.com/coreos/go-oidc/key/key.go
generated
vendored
Normal file
153
vendor/github.com/coreos/go-oidc/key/key.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
)
|
||||
|
||||
func NewPublicKey(jwk jose.JWK) *PublicKey {
|
||||
return &PublicKey{jwk: jwk}
|
||||
}
|
||||
|
||||
type PublicKey struct {
|
||||
jwk jose.JWK
|
||||
}
|
||||
|
||||
func (k *PublicKey) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&k.jwk)
|
||||
}
|
||||
|
||||
func (k *PublicKey) UnmarshalJSON(data []byte) error {
|
||||
var jwk jose.JWK
|
||||
if err := json.Unmarshal(data, &jwk); err != nil {
|
||||
return err
|
||||
}
|
||||
k.jwk = jwk
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *PublicKey) ID() string {
|
||||
return k.jwk.ID
|
||||
}
|
||||
|
||||
func (k *PublicKey) Verifier() (jose.Verifier, error) {
|
||||
return jose.NewVerifierRSA(k.jwk)
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
KeyID string
|
||||
PrivateKey *rsa.PrivateKey
|
||||
}
|
||||
|
||||
func (k *PrivateKey) ID() string {
|
||||
return k.KeyID
|
||||
}
|
||||
|
||||
func (k *PrivateKey) Signer() jose.Signer {
|
||||
return jose.NewSignerRSA(k.ID(), *k.PrivateKey)
|
||||
}
|
||||
|
||||
func (k *PrivateKey) JWK() jose.JWK {
|
||||
return jose.JWK{
|
||||
ID: k.KeyID,
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Exponent: k.PrivateKey.PublicKey.E,
|
||||
Modulus: k.PrivateKey.PublicKey.N,
|
||||
}
|
||||
}
|
||||
|
||||
type KeySet interface {
|
||||
ExpiresAt() time.Time
|
||||
}
|
||||
|
||||
type PublicKeySet struct {
|
||||
keys []PublicKey
|
||||
index map[string]*PublicKey
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
func NewPublicKeySet(jwks []jose.JWK, exp time.Time) *PublicKeySet {
|
||||
keys := make([]PublicKey, len(jwks))
|
||||
index := make(map[string]*PublicKey)
|
||||
for i, jwk := range jwks {
|
||||
keys[i] = *NewPublicKey(jwk)
|
||||
index[keys[i].ID()] = &keys[i]
|
||||
}
|
||||
return &PublicKeySet{
|
||||
keys: keys,
|
||||
index: index,
|
||||
expiresAt: exp,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PublicKeySet) ExpiresAt() time.Time {
|
||||
return s.expiresAt
|
||||
}
|
||||
|
||||
func (s *PublicKeySet) Keys() []PublicKey {
|
||||
return s.keys
|
||||
}
|
||||
|
||||
func (s *PublicKeySet) Key(id string) *PublicKey {
|
||||
return s.index[id]
|
||||
}
|
||||
|
||||
type PrivateKeySet struct {
|
||||
keys []*PrivateKey
|
||||
ActiveKeyID string
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
func NewPrivateKeySet(keys []*PrivateKey, exp time.Time) *PrivateKeySet {
|
||||
return &PrivateKeySet{
|
||||
keys: keys,
|
||||
ActiveKeyID: keys[0].ID(),
|
||||
expiresAt: exp.UTC(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PrivateKeySet) Keys() []*PrivateKey {
|
||||
return s.keys
|
||||
}
|
||||
|
||||
func (s *PrivateKeySet) ExpiresAt() time.Time {
|
||||
return s.expiresAt
|
||||
}
|
||||
|
||||
func (s *PrivateKeySet) Active() *PrivateKey {
|
||||
for i, k := range s.keys {
|
||||
if k.ID() == s.ActiveKeyID {
|
||||
return s.keys[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type GeneratePrivateKeyFunc func() (*PrivateKey, error)
|
||||
|
||||
func GeneratePrivateKey() (*PrivateKey, error) {
|
||||
pk, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyID := make([]byte, 20)
|
||||
if _, err := io.ReadFull(rand.Reader, keyID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k := PrivateKey{
|
||||
KeyID: hex.EncodeToString(keyID),
|
||||
PrivateKey: pk,
|
||||
}
|
||||
|
||||
return &k, nil
|
||||
}
|
103
vendor/github.com/coreos/go-oidc/key/key_test.go
generated
vendored
Normal file
103
vendor/github.com/coreos/go-oidc/key/key_test.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
)
|
||||
|
||||
func TestPrivateRSAKeyJWK(t *testing.T) {
|
||||
n := big.NewInt(int64(17))
|
||||
if n == nil {
|
||||
panic("NewInt returned nil")
|
||||
}
|
||||
|
||||
k := &PrivateKey{
|
||||
KeyID: "foo",
|
||||
PrivateKey: &rsa.PrivateKey{
|
||||
PublicKey: rsa.PublicKey{N: n, E: 65537},
|
||||
},
|
||||
}
|
||||
|
||||
want := jose.JWK{
|
||||
ID: "foo",
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Modulus: n,
|
||||
Exponent: 65537,
|
||||
}
|
||||
|
||||
got := k.JWK()
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("JWK mismatch: want=%#v got=%#v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicKeySetKey(t *testing.T) {
|
||||
n := big.NewInt(int64(17))
|
||||
if n == nil {
|
||||
panic("NewInt returned nil")
|
||||
}
|
||||
|
||||
k := jose.JWK{
|
||||
ID: "foo",
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Modulus: n,
|
||||
Exponent: 65537,
|
||||
}
|
||||
now := time.Now().UTC()
|
||||
ks := NewPublicKeySet([]jose.JWK{k}, now)
|
||||
|
||||
want := &PublicKey{jwk: k}
|
||||
got := ks.Key("foo")
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("Unexpected response from PublicKeySet.Key: want=%#v got=%#v", want, got)
|
||||
}
|
||||
|
||||
got = ks.Key("bar")
|
||||
if got != nil {
|
||||
t.Errorf("Expected nil response from PublicKeySet.Key, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicKeyMarshalJSON(t *testing.T) {
|
||||
k := jose.JWK{
|
||||
ID: "foo",
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Modulus: big.NewInt(int64(17)),
|
||||
Exponent: 65537,
|
||||
}
|
||||
want := `{"kid":"foo","kty":"RSA","alg":"RS256","use":"sig","e":"AQAB","n":"EQ"}`
|
||||
pubKey := NewPublicKey(k)
|
||||
gotBytes, err := pubKey.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal public key: %v", err)
|
||||
}
|
||||
got := string(gotBytes)
|
||||
if got != want {
|
||||
t.Errorf("got != want:\n%s\n%s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratePrivateKeyIDs(t *testing.T) {
|
||||
key1, err := GeneratePrivateKey()
|
||||
if err != nil {
|
||||
t.Fatalf("GeneratePrivateKey(): %v", err)
|
||||
}
|
||||
key2, err := GeneratePrivateKey()
|
||||
if err != nil {
|
||||
t.Fatalf("GeneratePrivateKey(): %v", err)
|
||||
}
|
||||
if key1.KeyID == key2.KeyID {
|
||||
t.Fatalf("expected different keys to have different key IDs")
|
||||
}
|
||||
}
|
99
vendor/github.com/coreos/go-oidc/key/manager.go
generated
vendored
Normal file
99
vendor/github.com/coreos/go-oidc/key/manager.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
"github.com/coreos/pkg/health"
|
||||
)
|
||||
|
||||
type PrivateKeyManager interface {
|
||||
ExpiresAt() time.Time
|
||||
Signer() (jose.Signer, error)
|
||||
JWKs() ([]jose.JWK, error)
|
||||
PublicKeys() ([]PublicKey, error)
|
||||
|
||||
WritableKeySetRepo
|
||||
health.Checkable
|
||||
}
|
||||
|
||||
func NewPrivateKeyManager() PrivateKeyManager {
|
||||
return &privateKeyManager{
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
type privateKeyManager struct {
|
||||
keySet *PrivateKeySet
|
||||
clock clockwork.Clock
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) ExpiresAt() time.Time {
|
||||
if m.keySet == nil {
|
||||
return m.clock.Now().UTC()
|
||||
}
|
||||
|
||||
return m.keySet.ExpiresAt()
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) Signer() (jose.Signer, error) {
|
||||
if err := m.Healthy(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m.keySet.Active().Signer(), nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) JWKs() ([]jose.JWK, error) {
|
||||
if err := m.Healthy(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keys := m.keySet.Keys()
|
||||
jwks := make([]jose.JWK, len(keys))
|
||||
for i, k := range keys {
|
||||
jwks[i] = k.JWK()
|
||||
}
|
||||
return jwks, nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) PublicKeys() ([]PublicKey, error) {
|
||||
jwks, err := m.JWKs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys := make([]PublicKey, len(jwks))
|
||||
for i, jwk := range jwks {
|
||||
keys[i] = *NewPublicKey(jwk)
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) Healthy() error {
|
||||
if m.keySet == nil {
|
||||
return errors.New("private key manager uninitialized")
|
||||
}
|
||||
|
||||
if len(m.keySet.Keys()) == 0 {
|
||||
return errors.New("private key manager zero keys")
|
||||
}
|
||||
|
||||
if m.keySet.ExpiresAt().Before(m.clock.Now().UTC()) {
|
||||
return errors.New("private key manager keys expired")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *privateKeyManager) Set(keySet KeySet) error {
|
||||
privKeySet, ok := keySet.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return errors.New("unable to cast to PrivateKeySet")
|
||||
}
|
||||
|
||||
m.keySet = privKeySet
|
||||
return nil
|
||||
}
|
225
vendor/github.com/coreos/go-oidc/key/manager_test.go
generated
vendored
Normal file
225
vendor/github.com/coreos/go-oidc/key/manager_test.go
generated
vendored
Normal file
|
@ -0,0 +1,225 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
"github.com/coreos/go-oidc/jose"
|
||||
)
|
||||
|
||||
var (
|
||||
jwk1 jose.JWK
|
||||
jwk2 jose.JWK
|
||||
jwk3 jose.JWK
|
||||
)
|
||||
|
||||
func init() {
|
||||
jwk1 = jose.JWK{
|
||||
ID: "1",
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Modulus: big.NewInt(1),
|
||||
Exponent: 65537,
|
||||
}
|
||||
|
||||
jwk2 = jose.JWK{
|
||||
ID: "2",
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Modulus: big.NewInt(2),
|
||||
Exponent: 65537,
|
||||
}
|
||||
|
||||
jwk3 = jose.JWK{
|
||||
ID: "3",
|
||||
Type: "RSA",
|
||||
Alg: "RS256",
|
||||
Use: "sig",
|
||||
Modulus: big.NewInt(3),
|
||||
Exponent: 65537,
|
||||
}
|
||||
}
|
||||
|
||||
func generatePrivateKeyStatic(t *testing.T, idAndN int) *PrivateKey {
|
||||
n := big.NewInt(int64(idAndN))
|
||||
if n == nil {
|
||||
t.Fatalf("Call to NewInt(%d) failed", idAndN)
|
||||
}
|
||||
|
||||
pk := &rsa.PrivateKey{
|
||||
PublicKey: rsa.PublicKey{N: n, E: 65537},
|
||||
}
|
||||
|
||||
return &PrivateKey{
|
||||
KeyID: strconv.Itoa(idAndN),
|
||||
PrivateKey: pk,
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyManagerJWKsRotate(t *testing.T) {
|
||||
k1 := generatePrivateKeyStatic(t, 1)
|
||||
k2 := generatePrivateKeyStatic(t, 2)
|
||||
k3 := generatePrivateKeyStatic(t, 3)
|
||||
km := NewPrivateKeyManager()
|
||||
err := km.Set(&PrivateKeySet{
|
||||
keys: []*PrivateKey{k1, k2, k3},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: time.Now().Add(time.Minute),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
want := []jose.JWK{jwk1, jwk2, jwk3}
|
||||
got, err := km.JWKs()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("JWK mismatch: want=%#v got=%#v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyManagerSigner(t *testing.T) {
|
||||
k := generatePrivateKeyStatic(t, 13)
|
||||
|
||||
km := NewPrivateKeyManager()
|
||||
err := km.Set(&PrivateKeySet{
|
||||
keys: []*PrivateKey{k},
|
||||
ActiveKeyID: k.KeyID,
|
||||
expiresAt: time.Now().Add(time.Minute),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
signer, err := km.Signer()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
wantID := "13"
|
||||
gotID := signer.ID()
|
||||
if wantID != gotID {
|
||||
t.Fatalf("Signer has incorrect ID: want=%s got=%s", wantID, gotID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyManagerHealthyFail(t *testing.T) {
|
||||
keyFixture := generatePrivateKeyStatic(t, 1)
|
||||
tests := []*privateKeyManager{
|
||||
// keySet nil
|
||||
&privateKeyManager{
|
||||
keySet: nil,
|
||||
clock: clockwork.NewRealClock(),
|
||||
},
|
||||
// zero keys
|
||||
&privateKeyManager{
|
||||
keySet: &PrivateKeySet{
|
||||
keys: []*PrivateKey{},
|
||||
expiresAt: time.Now().Add(time.Minute),
|
||||
},
|
||||
clock: clockwork.NewRealClock(),
|
||||
},
|
||||
// key set expired
|
||||
&privateKeyManager{
|
||||
keySet: &PrivateKeySet{
|
||||
keys: []*PrivateKey{keyFixture},
|
||||
expiresAt: time.Now().Add(-1 * time.Minute),
|
||||
},
|
||||
clock: clockwork.NewRealClock(),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
if err := tt.Healthy(); err == nil {
|
||||
t.Errorf("case %d: nil error", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyManagerHealthyFailsOtherMethods(t *testing.T) {
|
||||
km := NewPrivateKeyManager()
|
||||
if _, err := km.JWKs(); err == nil {
|
||||
t.Fatalf("Expected non-nil error")
|
||||
}
|
||||
if _, err := km.Signer(); err == nil {
|
||||
t.Fatalf("Expected non-nil error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyManagerExpiresAt(t *testing.T) {
|
||||
fc := clockwork.NewFakeClock()
|
||||
now := fc.Now().UTC()
|
||||
|
||||
k := generatePrivateKeyStatic(t, 17)
|
||||
km := &privateKeyManager{
|
||||
clock: fc,
|
||||
}
|
||||
|
||||
want := fc.Now().UTC()
|
||||
got := km.ExpiresAt()
|
||||
if want != got {
|
||||
t.Fatalf("Incorrect expiration time: want=%v got=%v", want, got)
|
||||
}
|
||||
|
||||
err := km.Set(&PrivateKeySet{
|
||||
keys: []*PrivateKey{k},
|
||||
ActiveKeyID: k.KeyID,
|
||||
expiresAt: now.Add(2 * time.Minute),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
want = fc.Now().UTC().Add(2 * time.Minute)
|
||||
got = km.ExpiresAt()
|
||||
if want != got {
|
||||
t.Fatalf("Incorrect expiration time: want=%v got=%v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicKeys(t *testing.T) {
|
||||
km := NewPrivateKeyManager()
|
||||
k1 := generatePrivateKeyStatic(t, 1)
|
||||
k2 := generatePrivateKeyStatic(t, 2)
|
||||
k3 := generatePrivateKeyStatic(t, 3)
|
||||
|
||||
tests := [][]*PrivateKey{
|
||||
[]*PrivateKey{k1},
|
||||
[]*PrivateKey{k1, k2},
|
||||
[]*PrivateKey{k1, k2, k3},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
ks := &PrivateKeySet{
|
||||
keys: tt,
|
||||
expiresAt: time.Now().Add(time.Hour),
|
||||
}
|
||||
km.Set(ks)
|
||||
|
||||
jwks, err := km.JWKs()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
pks := NewPublicKeySet(jwks, time.Now().Add(time.Hour))
|
||||
want := pks.Keys()
|
||||
got, err := km.PublicKeys()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("case %d: Invalid public keys: want=%v got=%v", i, want, got)
|
||||
}
|
||||
}
|
||||
}
|
55
vendor/github.com/coreos/go-oidc/key/repo.go
generated
vendored
Normal file
55
vendor/github.com/coreos/go-oidc/key/repo.go
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var ErrorNoKeys = errors.New("no keys found")
|
||||
|
||||
type WritableKeySetRepo interface {
|
||||
Set(KeySet) error
|
||||
}
|
||||
|
||||
type ReadableKeySetRepo interface {
|
||||
Get() (KeySet, error)
|
||||
}
|
||||
|
||||
type PrivateKeySetRepo interface {
|
||||
WritableKeySetRepo
|
||||
ReadableKeySetRepo
|
||||
}
|
||||
|
||||
func NewPrivateKeySetRepo() PrivateKeySetRepo {
|
||||
return &memPrivateKeySetRepo{}
|
||||
}
|
||||
|
||||
type memPrivateKeySetRepo struct {
|
||||
mu sync.RWMutex
|
||||
pks PrivateKeySet
|
||||
}
|
||||
|
||||
func (r *memPrivateKeySetRepo) Set(ks KeySet) error {
|
||||
pks, ok := ks.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return errors.New("unable to cast to PrivateKeySet")
|
||||
} else if pks == nil {
|
||||
return errors.New("nil KeySet")
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
r.pks = *pks
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *memPrivateKeySetRepo) Get() (KeySet, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
if r.pks.keys == nil {
|
||||
return nil, ErrorNoKeys
|
||||
}
|
||||
return KeySet(&r.pks), nil
|
||||
}
|
159
vendor/github.com/coreos/go-oidc/key/rotate.go
generated
vendored
Normal file
159
vendor/github.com/coreos/go-oidc/key/rotate.go
generated
vendored
Normal file
|
@ -0,0 +1,159 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
ptime "github.com/coreos/pkg/timeutil"
|
||||
"github.com/jonboulle/clockwork"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorPrivateKeysExpired = errors.New("private keys have expired")
|
||||
)
|
||||
|
||||
func NewPrivateKeyRotator(repo PrivateKeySetRepo, ttl time.Duration) *PrivateKeyRotator {
|
||||
return &PrivateKeyRotator{
|
||||
repo: repo,
|
||||
ttl: ttl,
|
||||
|
||||
keep: 2,
|
||||
generateKey: GeneratePrivateKey,
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
type PrivateKeyRotator struct {
|
||||
repo PrivateKeySetRepo
|
||||
generateKey GeneratePrivateKeyFunc
|
||||
clock clockwork.Clock
|
||||
keep int
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) expiresAt() time.Time {
|
||||
return r.clock.Now().UTC().Add(r.ttl)
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) Healthy() error {
|
||||
pks, err := r.privateKeySet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.clock.Now().After(pks.ExpiresAt()) {
|
||||
return ErrorPrivateKeysExpired
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) privateKeySet() (*PrivateKeySet, error) {
|
||||
ks, err := r.repo.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pks, ok := ks.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return nil, errors.New("unable to cast to PrivateKeySet")
|
||||
}
|
||||
return pks, nil
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) nextRotation() (time.Duration, error) {
|
||||
pks, err := r.privateKeySet()
|
||||
if err == ErrorNoKeys {
|
||||
return 0, nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
now := r.clock.Now()
|
||||
|
||||
// Ideally, we want to rotate after half the TTL has elapsed.
|
||||
idealRotationTime := pks.ExpiresAt().Add(-r.ttl / 2)
|
||||
|
||||
// If we are past the ideal rotation time, rotate immediatly.
|
||||
return max(0, idealRotationTime.Sub(now)), nil
|
||||
}
|
||||
|
||||
func max(a, b time.Duration) time.Duration {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (r *PrivateKeyRotator) Run() chan struct{} {
|
||||
attempt := func() {
|
||||
k, err := r.generateKey()
|
||||
if err != nil {
|
||||
log.Printf("go-oidc: failed generating signing key: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
exp := r.expiresAt()
|
||||
if err := rotatePrivateKeys(r.repo, k, r.keep, exp); err != nil {
|
||||
log.Printf("go-oidc: key rotation failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
stop := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
var nextRotation time.Duration
|
||||
var sleep time.Duration
|
||||
var err error
|
||||
for {
|
||||
if nextRotation, err = r.nextRotation(); err == nil {
|
||||
break
|
||||
}
|
||||
sleep = ptime.ExpBackoff(sleep, time.Minute)
|
||||
log.Printf("go-oidc: error getting nextRotation, retrying in %v: %v", sleep, err)
|
||||
time.Sleep(sleep)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-r.clock.After(nextRotation):
|
||||
attempt()
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return stop
|
||||
}
|
||||
|
||||
func rotatePrivateKeys(repo PrivateKeySetRepo, k *PrivateKey, keep int, exp time.Time) error {
|
||||
ks, err := repo.Get()
|
||||
if err != nil && err != ErrorNoKeys {
|
||||
return err
|
||||
}
|
||||
|
||||
var keys []*PrivateKey
|
||||
if ks != nil {
|
||||
pks, ok := ks.(*PrivateKeySet)
|
||||
if !ok {
|
||||
return errors.New("unable to cast to PrivateKeySet")
|
||||
}
|
||||
keys = pks.Keys()
|
||||
}
|
||||
|
||||
keys = append([]*PrivateKey{k}, keys...)
|
||||
if l := len(keys); l > keep {
|
||||
keys = keys[0:keep]
|
||||
}
|
||||
|
||||
nks := PrivateKeySet{
|
||||
keys: keys,
|
||||
ActiveKeyID: k.ID(),
|
||||
expiresAt: exp,
|
||||
}
|
||||
|
||||
return repo.Set(KeySet(&nks))
|
||||
}
|
311
vendor/github.com/coreos/go-oidc/key/rotate_test.go
generated
vendored
Normal file
311
vendor/github.com/coreos/go-oidc/key/rotate_test.go
generated
vendored
Normal file
|
@ -0,0 +1,311 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
)
|
||||
|
||||
func generatePrivateKeySerialFunc(t *testing.T) GeneratePrivateKeyFunc {
|
||||
var n int
|
||||
return func() (*PrivateKey, error) {
|
||||
n++
|
||||
return generatePrivateKeyStatic(t, n), nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotate(t *testing.T) {
|
||||
now := time.Now()
|
||||
k1 := generatePrivateKeyStatic(t, 1)
|
||||
k2 := generatePrivateKeyStatic(t, 2)
|
||||
k3 := generatePrivateKeyStatic(t, 3)
|
||||
|
||||
tests := []struct {
|
||||
start *PrivateKeySet
|
||||
key *PrivateKey
|
||||
keep int
|
||||
exp time.Time
|
||||
want *PrivateKeySet
|
||||
}{
|
||||
// start with nil keys
|
||||
{
|
||||
start: nil,
|
||||
key: k1,
|
||||
keep: 2,
|
||||
exp: now.Add(time.Second),
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now.Add(time.Second),
|
||||
},
|
||||
},
|
||||
// start with zero keys
|
||||
{
|
||||
start: &PrivateKeySet{},
|
||||
key: k1,
|
||||
keep: 2,
|
||||
exp: now.Add(time.Second),
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now.Add(time.Second),
|
||||
},
|
||||
},
|
||||
// add second key
|
||||
{
|
||||
start: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now,
|
||||
},
|
||||
key: k2,
|
||||
keep: 2,
|
||||
exp: now.Add(time.Second),
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(time.Second),
|
||||
},
|
||||
},
|
||||
// rotate in third key
|
||||
{
|
||||
start: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now,
|
||||
},
|
||||
key: k3,
|
||||
keep: 2,
|
||||
exp: now.Add(time.Second),
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k3, k2},
|
||||
ActiveKeyID: k3.KeyID,
|
||||
expiresAt: now.Add(time.Second),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
repo := NewPrivateKeySetRepo()
|
||||
if tt.start != nil {
|
||||
err := repo.Set(tt.start)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: unexpected error: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
rotatePrivateKeys(repo, tt.key, tt.keep, tt.exp)
|
||||
got, err := repo.Get()
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(tt.want, got) {
|
||||
t.Errorf("case %d: unexpected result: want=%#v got=%#v", i, tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyRotatorRun(t *testing.T) {
|
||||
fc := clockwork.NewFakeClock()
|
||||
now := fc.Now().UTC()
|
||||
|
||||
k1 := generatePrivateKeyStatic(t, 1)
|
||||
k2 := generatePrivateKeyStatic(t, 2)
|
||||
k3 := generatePrivateKeyStatic(t, 3)
|
||||
k4 := generatePrivateKeyStatic(t, 4)
|
||||
|
||||
kRepo := NewPrivateKeySetRepo()
|
||||
krot := NewPrivateKeyRotator(kRepo, 4*time.Second)
|
||||
krot.clock = fc
|
||||
krot.generateKey = generatePrivateKeySerialFunc(t)
|
||||
|
||||
steps := []*PrivateKeySet{
|
||||
&PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now.Add(4 * time.Second),
|
||||
},
|
||||
&PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(6 * time.Second),
|
||||
},
|
||||
&PrivateKeySet{
|
||||
keys: []*PrivateKey{k3, k2},
|
||||
ActiveKeyID: k3.KeyID,
|
||||
expiresAt: now.Add(8 * time.Second),
|
||||
},
|
||||
&PrivateKeySet{
|
||||
keys: []*PrivateKey{k4, k3},
|
||||
ActiveKeyID: k4.KeyID,
|
||||
expiresAt: now.Add(10 * time.Second),
|
||||
},
|
||||
}
|
||||
|
||||
stop := krot.Run()
|
||||
defer close(stop)
|
||||
|
||||
for i, st := range steps {
|
||||
// wait for the rotater to get sleepy
|
||||
fc.BlockUntil(1)
|
||||
|
||||
got, err := kRepo.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("step %d: unexpected error: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(st, got) {
|
||||
t.Fatalf("step %d: unexpected state: want=%#v got=%#v", i, st, got)
|
||||
}
|
||||
fc.Advance(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyRotatorExpiresAt(t *testing.T) {
|
||||
fc := clockwork.NewFakeClock()
|
||||
krot := &PrivateKeyRotator{
|
||||
clock: fc,
|
||||
ttl: time.Minute,
|
||||
}
|
||||
got := krot.expiresAt()
|
||||
want := fc.Now().UTC().Add(time.Minute)
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Errorf("Incorrect expiration time: want=%v got=%v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextRotation(t *testing.T) {
|
||||
fc := clockwork.NewFakeClock()
|
||||
now := fc.Now().UTC()
|
||||
|
||||
tests := []struct {
|
||||
expiresAt time.Time
|
||||
ttl time.Duration
|
||||
numKeys int
|
||||
expected time.Duration
|
||||
}{
|
||||
{
|
||||
// closest to prod
|
||||
expiresAt: now.Add(time.Hour * 24),
|
||||
ttl: time.Hour * 24,
|
||||
numKeys: 2,
|
||||
expected: time.Hour * 12,
|
||||
},
|
||||
{
|
||||
expiresAt: now.Add(time.Hour * 2),
|
||||
ttl: time.Hour * 4,
|
||||
numKeys: 2,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
// No keys.
|
||||
expiresAt: now.Add(time.Hour * 2),
|
||||
ttl: time.Hour * 4,
|
||||
numKeys: 0,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
// Nil keyset.
|
||||
expiresAt: now.Add(time.Hour * 2),
|
||||
ttl: time.Hour * 4,
|
||||
numKeys: -1,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
// KeySet expired.
|
||||
expiresAt: now.Add(time.Hour * -2),
|
||||
ttl: time.Hour * 4,
|
||||
numKeys: 2,
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
// Expiry past now + TTL
|
||||
expiresAt: now.Add(time.Hour * 5),
|
||||
ttl: time.Hour * 4,
|
||||
numKeys: 2,
|
||||
expected: 3 * time.Hour,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
kRepo := NewPrivateKeySetRepo()
|
||||
krot := NewPrivateKeyRotator(kRepo, tt.ttl)
|
||||
krot.clock = fc
|
||||
pks := &PrivateKeySet{
|
||||
expiresAt: tt.expiresAt,
|
||||
}
|
||||
if tt.numKeys != -1 {
|
||||
for n := 0; n < tt.numKeys; n++ {
|
||||
pks.keys = append(pks.keys, generatePrivateKeyStatic(t, n))
|
||||
}
|
||||
err := kRepo.Set(pks)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: unexpected error: %v", i, err)
|
||||
}
|
||||
|
||||
}
|
||||
actual, err := krot.nextRotation()
|
||||
if err != nil {
|
||||
t.Errorf("case %d: error calling shouldRotate(): %v", i, err)
|
||||
}
|
||||
if actual != tt.expected {
|
||||
t.Errorf("case %d: actual == %v, want %v", i, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthy(t *testing.T) {
|
||||
fc := clockwork.NewFakeClock()
|
||||
now := fc.Now().UTC()
|
||||
|
||||
tests := []struct {
|
||||
expiresAt time.Time
|
||||
numKeys int
|
||||
expected error
|
||||
}{
|
||||
{
|
||||
expiresAt: now.Add(time.Hour),
|
||||
numKeys: 2,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
expiresAt: now.Add(time.Hour),
|
||||
numKeys: -1,
|
||||
expected: ErrorNoKeys,
|
||||
},
|
||||
{
|
||||
expiresAt: now.Add(time.Hour),
|
||||
numKeys: 0,
|
||||
expected: ErrorNoKeys,
|
||||
},
|
||||
{
|
||||
expiresAt: now.Add(-time.Hour),
|
||||
numKeys: 2,
|
||||
expected: ErrorPrivateKeysExpired,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
kRepo := NewPrivateKeySetRepo()
|
||||
krot := NewPrivateKeyRotator(kRepo, time.Hour)
|
||||
krot.clock = fc
|
||||
pks := &PrivateKeySet{
|
||||
expiresAt: tt.expiresAt,
|
||||
}
|
||||
if tt.numKeys != -1 {
|
||||
for n := 0; n < tt.numKeys; n++ {
|
||||
pks.keys = append(pks.keys, generatePrivateKeyStatic(t, n))
|
||||
}
|
||||
err := kRepo.Set(pks)
|
||||
if err != nil {
|
||||
t.Fatalf("case %d: unexpected error: %v", i, err)
|
||||
}
|
||||
|
||||
}
|
||||
if err := krot.Healthy(); err != tt.expected {
|
||||
t.Errorf("case %d: got==%q, want==%q", i, err, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
91
vendor/github.com/coreos/go-oidc/key/sync.go
generated
vendored
Normal file
91
vendor/github.com/coreos/go-oidc/key/sync.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
"github.com/coreos/pkg/timeutil"
|
||||
)
|
||||
|
||||
func NewKeySetSyncer(r ReadableKeySetRepo, w WritableKeySetRepo) *KeySetSyncer {
|
||||
return &KeySetSyncer{
|
||||
readable: r,
|
||||
writable: w,
|
||||
clock: clockwork.NewRealClock(),
|
||||
}
|
||||
}
|
||||
|
||||
type KeySetSyncer struct {
|
||||
readable ReadableKeySetRepo
|
||||
writable WritableKeySetRepo
|
||||
clock clockwork.Clock
|
||||
}
|
||||
|
||||
func (s *KeySetSyncer) Run() chan struct{} {
|
||||
stop := make(chan struct{})
|
||||
go func() {
|
||||
var failing bool
|
||||
var next time.Duration
|
||||
for {
|
||||
exp, err := syncKeySet(s.readable, s.writable, s.clock)
|
||||
if err != nil || exp == 0 {
|
||||
if !failing {
|
||||
failing = true
|
||||
next = time.Second
|
||||
} else {
|
||||
next = timeutil.ExpBackoff(next, time.Minute)
|
||||
}
|
||||
if exp == 0 {
|
||||
log.Printf("Synced to already expired key set, retrying in %v: %v", next, err)
|
||||
|
||||
} else {
|
||||
log.Printf("Failed syncing key set, retrying in %v: %v", next, err)
|
||||
}
|
||||
} else {
|
||||
failing = false
|
||||
next = exp / 2
|
||||
}
|
||||
|
||||
select {
|
||||
case <-s.clock.After(next):
|
||||
continue
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return stop
|
||||
}
|
||||
|
||||
func Sync(r ReadableKeySetRepo, w WritableKeySetRepo) (time.Duration, error) {
|
||||
return syncKeySet(r, w, clockwork.NewRealClock())
|
||||
}
|
||||
|
||||
// syncKeySet copies the keyset from r to the KeySet at w and returns the duration in which the KeySet will expire.
|
||||
// If keyset has already expired, returns a zero duration.
|
||||
func syncKeySet(r ReadableKeySetRepo, w WritableKeySetRepo, clock clockwork.Clock) (exp time.Duration, err error) {
|
||||
var ks KeySet
|
||||
ks, err = r.Get()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ks == nil {
|
||||
err = errors.New("no source KeySet")
|
||||
return
|
||||
}
|
||||
|
||||
if err = w.Set(ks); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
now := clock.Now()
|
||||
if ks.ExpiresAt().After(now) {
|
||||
exp = ks.ExpiresAt().Sub(now)
|
||||
}
|
||||
return
|
||||
}
|
214
vendor/github.com/coreos/go-oidc/key/sync_test.go
generated
vendored
Normal file
214
vendor/github.com/coreos/go-oidc/key/sync_test.go
generated
vendored
Normal file
|
@ -0,0 +1,214 @@
|
|||
package key
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
)
|
||||
|
||||
type staticReadableKeySetRepo struct {
|
||||
mu sync.RWMutex
|
||||
ks KeySet
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *staticReadableKeySetRepo) Get() (KeySet, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
return r.ks, r.err
|
||||
}
|
||||
|
||||
func (r *staticReadableKeySetRepo) set(ks KeySet, err error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.ks, r.err = ks, err
|
||||
}
|
||||
|
||||
func TestKeySyncerSync(t *testing.T) {
|
||||
fc := clockwork.NewFakeClock()
|
||||
now := fc.Now().UTC()
|
||||
|
||||
k1 := generatePrivateKeyStatic(t, 1)
|
||||
k2 := generatePrivateKeyStatic(t, 2)
|
||||
k3 := generatePrivateKeyStatic(t, 3)
|
||||
|
||||
steps := []struct {
|
||||
fromKS KeySet
|
||||
fromErr error
|
||||
advance time.Duration
|
||||
want *PrivateKeySet
|
||||
}{
|
||||
// on startup, first sync should trigger within a second
|
||||
{
|
||||
fromKS: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now.Add(10 * time.Second),
|
||||
},
|
||||
advance: time.Second,
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now.Add(10 * time.Second),
|
||||
},
|
||||
},
|
||||
// advance halfway into TTL, triggering sync
|
||||
{
|
||||
fromKS: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(15 * time.Second),
|
||||
},
|
||||
advance: 5 * time.Second,
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(15 * time.Second),
|
||||
},
|
||||
},
|
||||
|
||||
// advance halfway into TTL, triggering sync that fails
|
||||
{
|
||||
fromErr: errors.New("fail!"),
|
||||
advance: 10 * time.Second,
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(15 * time.Second),
|
||||
},
|
||||
},
|
||||
|
||||
// sync retries quickly, and succeeds with fixed data
|
||||
{
|
||||
fromKS: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k3, k2, k1},
|
||||
ActiveKeyID: k3.KeyID,
|
||||
expiresAt: now.Add(25 * time.Second),
|
||||
},
|
||||
advance: 3 * time.Second,
|
||||
want: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k3, k2, k1},
|
||||
ActiveKeyID: k3.KeyID,
|
||||
expiresAt: now.Add(25 * time.Second),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
from := &staticReadableKeySetRepo{}
|
||||
to := NewPrivateKeySetRepo()
|
||||
|
||||
syncer := NewKeySetSyncer(from, to)
|
||||
syncer.clock = fc
|
||||
stop := syncer.Run()
|
||||
defer close(stop)
|
||||
|
||||
for i, st := range steps {
|
||||
from.set(st.fromKS, st.fromErr)
|
||||
|
||||
fc.Advance(st.advance)
|
||||
fc.BlockUntil(1)
|
||||
|
||||
ks, err := to.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("step %d: unable to get keys: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(st.want, ks) {
|
||||
t.Fatalf("step %d: incorrect state: want=%#v got=%#v", i, st.want, ks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSync(t *testing.T) {
|
||||
fc := clockwork.NewFakeClock()
|
||||
now := fc.Now().UTC()
|
||||
|
||||
k1 := generatePrivateKeyStatic(t, 1)
|
||||
k2 := generatePrivateKeyStatic(t, 2)
|
||||
k3 := generatePrivateKeyStatic(t, 3)
|
||||
|
||||
tests := []struct {
|
||||
keySet *PrivateKeySet
|
||||
want time.Duration
|
||||
}{
|
||||
{
|
||||
keySet: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now.Add(time.Minute),
|
||||
},
|
||||
want: time.Minute,
|
||||
},
|
||||
{
|
||||
keySet: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(time.Minute),
|
||||
},
|
||||
want: time.Minute,
|
||||
},
|
||||
{
|
||||
keySet: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k3, k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(time.Minute),
|
||||
},
|
||||
want: time.Minute,
|
||||
},
|
||||
{
|
||||
keySet: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k2, k1},
|
||||
ActiveKeyID: k2.KeyID,
|
||||
expiresAt: now.Add(time.Hour),
|
||||
},
|
||||
want: time.Hour,
|
||||
},
|
||||
{
|
||||
keySet: &PrivateKeySet{
|
||||
keys: []*PrivateKey{k1},
|
||||
ActiveKeyID: k1.KeyID,
|
||||
expiresAt: now.Add(-time.Hour),
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
from := NewPrivateKeySetRepo()
|
||||
to := NewPrivateKeySetRepo()
|
||||
|
||||
err := from.Set(tt.keySet)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
exp, err := syncKeySet(from, to, fc)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if tt.want != exp {
|
||||
t.Errorf("case %d: want=%v got=%v", i, tt.want, exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncFail(t *testing.T) {
|
||||
tests := []error{
|
||||
nil,
|
||||
errors.New("fail!"),
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
from := &staticReadableKeySetRepo{ks: nil, err: tt}
|
||||
to := NewPrivateKeySetRepo()
|
||||
|
||||
if _, err := syncKeySet(from, to, clockwork.NewFakeClock()); err == nil {
|
||||
t.Errorf("case %d: expected non-nil error", i)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue