Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added signing keys to operator claims. #12

Merged
merged 3 commits into from
Nov 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion operator_claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,25 @@ import (

// Operator specific claims
type Operator struct {
Identities []Identity `json:"identity,omitempty"`
Identities []Identity `json:"identity,omitempty"`
SigningKeys []string `json:"signing_keys,omitempty"`
}

// Validate checks the validity of the operators contents
func (o *Operator) Validate(vr *ValidationResults) {
for _, i := range o.Identities {
i.Validate(vr)
}

if o.SigningKeys == nil {
return
}

for _, k := range o.SigningKeys {
if !nkeys.IsValidPublicOperatorKey([]byte(k)) {
vr.AddError("%s is not an operator public key", k)
}
}
}

// OperatorClaims define the data for an operator JWT
Expand All @@ -34,6 +45,39 @@ func NewOperatorClaims(subject string) *OperatorClaims {
return c
}

// DidSign checks the claims against the operator's public key and its signing keys
func (s *OperatorClaims) DidSign(op Claims) bool {
if op == nil {
return false
}

issuer := op.Claims().Issuer

if issuer == s.Subject {
return true
}

for _, k := range s.SigningKeys {
if k == issuer {
return true
}
}

return false
}

// AddSigningKey creates the signing keys array if necessary
// appends the new key, NO Validation is performed
func (s *OperatorClaims) AddSigningKey(pk string) {

if s.SigningKeys == nil {
s.SigningKeys = []string{pk}
return
}

s.SigningKeys = append(s.SigningKeys, pk)
}

// Encode the claims into a JWT string
func (s *OperatorClaims) Encode(pair nkeys.KeyPair) (string, error) {
if !nkeys.IsValidPublicOperatorKey(([]byte(s.Subject))) {
Expand Down
83 changes: 83 additions & 0 deletions operator_claims_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,86 @@ func TestOperatorType(t *testing.T) {
}

}

func TestSigningKeyValidation(t *testing.T) {
ckp := createOperatorNKey(t)
ckp2 := createOperatorNKey(t)

uc := NewOperatorClaims(publicKey(ckp, t))
uc.Expires = time.Now().Add(time.Duration(time.Hour)).Unix()
uc.AddSigningKey(publicKey(ckp2, t))
uJwt := encode(uc, ckp, t)

uc2, err := DecodeOperatorClaims(uJwt)
if err != nil {
t.Fatal("failed to decode", err)
}

AssertEquals(len(uc2.SigningKeys), 1, t)
AssertEquals(uc2.SigningKeys[0] == publicKey(ckp2, t), true, t)

vr := &ValidationResults{}
uc.Validate(vr)

if len(vr.Issues) != 0 {
t.Fatal("valid operator key should have no validation issues")
}

uc.AddSigningKey("") // add an invalid one

vr = &ValidationResults{}
uc.Validate(vr)
if len(vr.Issues) == 0 {
t.Fatal("bad signing key should be invalid")
}
}

func TestSignedBy(t *testing.T) {
ckp := createOperatorNKey(t)
ckp2 := createOperatorNKey(t)

uc := NewOperatorClaims(publicKey(ckp, t))
uc2 := NewOperatorClaims(publicKey(ckp2, t))

akp := createAccountNKey(t)
ac := NewAccountClaims(publicKey(akp, t))
enc, err := ac.Encode(ckp) // sign with the operator key
if err != nil {
t.Fatal("failed to encode", err)
}
ac, err = DecodeAccountClaims(enc)
if err != nil {
t.Fatal("failed to decode", err)
}

AssertEquals(uc.DidSign(ac), true, t)
AssertEquals(uc2.DidSign(ac), false, t)

enc, err = ac.Encode(ckp2) // sign with the other operator key
if err != nil {
t.Fatal("failed to encode", err)
}
ac, err = DecodeAccountClaims(enc)
if err != nil {
t.Fatal("failed to decode", err)
}

AssertEquals(uc.DidSign(ac), false, t) // no signing key
AssertEquals(uc2.DidSign(ac), true, t) // actual key
uc.AddSigningKey(publicKey(ckp2, t))
AssertEquals(uc.DidSign(ac), true, t) // signing key

clusterKey := createClusterNKey(t)
clusterClaims := NewClusterClaims(publicKey(clusterKey, t))
enc, err = clusterClaims.Encode(ckp2) // sign with the operator key
if err != nil {
t.Fatal("failed to encode", err)
}
clusterClaims, err = DecodeClusterClaims(enc)
if err != nil {
t.Fatal("failed to decode", err)
}

AssertEquals(uc.DidSign(clusterClaims), true, t) // signing key
AssertEquals(uc2.DidSign(clusterClaims), true, t) // actual key
}