Skip to content

Commit

Permalink
[FEAT] import operator
Browse files Browse the repository at this point in the history
FIX #9
  • Loading branch information
aricart committed Nov 7, 2023
1 parent 962c04d commit 912eb9a
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 1 deletion.
46 changes: 46 additions & 0 deletions auth.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nats_auth

import (
"fmt"
"github.com/nats-io/jwt/v2"
"github.com/nats-io/nkeys"
)
Expand Down Expand Up @@ -79,6 +80,51 @@ func (a *OperatorsImpl) Delete(name string) error {
return nil
}

func (a *OperatorsImpl) Import(token []byte, keys []string) (Operator, error) {
claim, err := jwt.DecodeOperatorClaims(string(token))
if err != nil {
return nil, err
}

// we require all the keys? - new NGS will not allow you to
// edit configs via CLI, so this is not a problem?
m := make(map[string]*Key, len(keys))
for i, k := range keys {
key, err := KeyFrom(k, nkeys.PrefixByteOperator, nkeys.PrefixByteSeed)
if err != nil {
return nil, fmt.Errorf("invalid seed at %d: %w", i, err)
}
if key.Public != claim.Subject && !claim.SigningKeys.Contains(key.Public) {
return nil, fmt.Errorf("invalid seed %s: is not referenced by the operator", k)
}
m[key.Public] = key
}
if len(keys) != len(claim.SigningKeys)+1 {
return nil, fmt.Errorf("not all keys are provided: %d", len(keys))
}

var ok bool
data := &OperatorData{}
data.Claim = claim
data.EntityName = claim.Name
data.Key, ok = m[claim.Subject]
if !ok {
return nil, fmt.Errorf("%s was not provided", claim.Subject)
}
for _, k := range claim.SigningKeys {
key, ok := m[k]
if !ok {
return nil, fmt.Errorf("%s was not provided", k)
}
data.OperatorSigningKeys = append(data.OperatorSigningKeys, key)
}
a.auth.operators = append(a.auth.operators, data)
if err := data.update(); err != nil {
return nil, err
}
return data, nil
}

func (a *AuthImpl) Commit() error {
return a.provider.Store(a.operators)
}
Expand Down
34 changes: 33 additions & 1 deletion tests/operator_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tests

import (
"github.com/nats-io/jwt/v2"
"github.com/nats-io/nkeys"
"github.com/stretchr/testify/require"
"github.com/synadia-io/jwt-auth-builder.go"
)
Expand All @@ -11,7 +13,6 @@ func (suite *ProviderSuite) Test_OperatorBasics() {
require.NoError(t, err)

operators := auth.Operators()
require.NoError(t, err)
require.Empty(t, operators.List())

o := auth.Operators().Get("O")
Expand Down Expand Up @@ -210,3 +211,34 @@ func (suite *ProviderSuite) Test_OperatorSystemAccount() {
require.Nil(t, o.SystemAccount())
require.NoError(t, o.Accounts().Delete("SYS"))
}

func (suite *ProviderSuite) Test_OperatorImport() {
t := suite.T()
auth, err := nats_auth.NewAuth(suite.Provider)
require.NoError(t, err)

kp, err := nats_auth.KeyFor(nkeys.PrefixByteOperator)
require.NoError(t, err)

oc := jwt.NewOperatorClaims(kp.Public)
oc.Name = "O"
skp, err := nats_auth.KeyFor(nkeys.PrefixByteOperator)
require.NoError(t, err)
oc.SigningKeys.Add(skp.Public)

token, err := oc.Encode(kp.Pair)
require.NoError(t, err)

o, err := auth.Operators().Import(
[]byte(token),
[]string{string(kp.Seed), string(skp.Seed)})
require.NoError(t, err)
require.NotNil(t, o)

require.NoError(t, auth.Commit())
require.NoError(t, auth.Reload())
o = auth.Operators().Get("O")
require.NotNil(t, o)
require.Equal(t, kp.Public, o.Subject())
require.Equal(t, skp.Public, o.SigningKeys().List()[0])
}
2 changes: 2 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ type Operators interface {
Get(name string) Operator
// Delete an Operator by name or matching the specified ID
Delete(name string) error
// Import an Operator from JWT bytes and keys
Import(jwt []byte, keys []string) (Operator, error)
}

// Operator is an interface for editing the operator
Expand Down

0 comments on commit 912eb9a

Please sign in to comment.