github.com/nats-io/nsc@v0.0.0-20221206222106-35db9400b257/cmd/editscopedsk.go (about)

     1  /*
     2   * Copyright 2018-2021 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"github.com/nats-io/jwt/v2"
    22  	"github.com/nats-io/nkeys"
    23  	"github.com/nats-io/nsc/cmd/store"
    24  	"github.com/spf13/cobra"
    25  )
    26  
    27  func createEditSkopedSkCmd() *cobra.Command {
    28  	var params EditScopedSkParams
    29  	cmd := &cobra.Command{
    30  		Use:   "signing-key",
    31  		Short: "Edit a scoped signing key or promote a signing key to be scoped",
    32  		Long: `# Edit permissions associated with the account (n) signing key (sk):
    33  nsc edit signing-key --account <n> --sk <sk> --allow-pubsub <subject>,...
    34  nsc edit signing-key --account <n> --sk <sk> --allow-pub <subject>,...
    35  nsc edit signing-key --account <n> --sk <sk> --allow-sub <subject>,...
    36  `,
    37  		Args:         cobra.MaximumNArgs(1),
    38  		SilenceUsage: true,
    39  		RunE: func(cmd *cobra.Command, args []string) error {
    40  			return RunAction(cmd, args, &params)
    41  		},
    42  	}
    43  	cmd.Flags().StringVarP(&params.skName, "sk", "", "", "signing key to set scope for or role name for already existing scoped signing key")
    44  	cmd.Flags().StringVarP(&params.role, "role", "", "", "role associated with the signing key scope")
    45  	params.AccountContextParams.BindFlags(cmd)
    46  	params.UserPermissionLimits.BindFlags(cmd)
    47  	return cmd
    48  }
    49  
    50  func init() {
    51  	editCmd.AddCommand(createEditSkopedSkCmd())
    52  }
    53  
    54  type EditScopedSkParams struct {
    55  	skName string
    56  	role   string
    57  	claim  *jwt.AccountClaims
    58  	UserPermissionLimits
    59  	AccountContextParams
    60  	SignerParams
    61  }
    62  
    63  func (p *EditScopedSkParams) SetDefaults(ctx ActionCtx) error {
    64  	p.skName = NameFlagOrArgument(p.skName, ctx)
    65  	if err := p.AccountContextParams.SetDefaults(ctx); err != nil {
    66  		return err
    67  	}
    68  	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
    69  	return nil
    70  }
    71  
    72  func (p *EditScopedSkParams) PreInteractive(ctx ActionCtx) error {
    73  	return nil
    74  }
    75  
    76  func (p *EditScopedSkParams) Load(ctx ActionCtx) error {
    77  	var err error
    78  
    79  	if err = p.AccountContextParams.Validate(ctx); err != nil {
    80  		return err
    81  	}
    82  
    83  	if p.skName == "" {
    84  		ctx.CurrentCmd().SilenceUsage = false
    85  		return fmt.Errorf("signing key is required")
    86  	}
    87  
    88  	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
    89  	if err != nil {
    90  		return err
    91  	}
    92  
    93  	s, found := p.claim.SigningKeys.GetScope(p.skName)
    94  	if !found {
    95  		kp := keyByRoleName(ctx.StoreCtx().KeyStore, p.claim, p.skName)
    96  		if kp == nil {
    97  			// Couldn't find key by role name.
    98  			// Try resolving seed, public key, or filepath.
    99  			kp, err = store.ResolveKey(p.skName)
   100  			if err != nil {
   101  				return err
   102  			}
   103  		}
   104  		if kp == nil {
   105  			// Still don't have a key pair, give up.
   106  			return fmt.Errorf("signing-key not found")
   107  		}
   108  
   109  		p.skName, err = kp.PublicKey()
   110  		if err != nil {
   111  			return fmt.Errorf("signing-key public key error: %s", err)
   112  		}
   113  	}
   114  	if s == nil {
   115  		s = &jwt.UserScope{}
   116  	}
   117  	return p.UserPermissionLimits.Load(ctx, s.(*jwt.UserScope).Template)
   118  }
   119  
   120  func (p *EditScopedSkParams) PostInteractive(ctx ActionCtx) error {
   121  	return nil
   122  }
   123  
   124  func (p *EditScopedSkParams) Validate(ctx ActionCtx) error {
   125  	p.UserPermissionLimits.Validate(ctx)
   126  
   127  	if err := p.SignerParams.ResolveWithPriority(ctx, p.claim.Issuer); err != nil {
   128  		return err
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  func (p *EditScopedSkParams) Run(ctx ActionCtx) (store.Status, error) {
   135  	r := store.NewDetailedReport(true)
   136  	r.ReportSum = false
   137  	scope, _ := p.claim.SigningKeys.GetScope(p.skName)
   138  	if scope == nil {
   139  		scope = jwt.NewUserScope()
   140  		scope.(*jwt.UserScope).Key = p.skName
   141  	}
   142  	if ctx.AnySet("role") {
   143  		scope.(*jwt.UserScope).Role = p.role
   144  	}
   145  	s, err := p.UserPermissionLimits.Run(ctx, &(scope.(*jwt.UserScope).Template))
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	if s != nil {
   150  		r.Add(s.Details...)
   151  	}
   152  	p.claim.SigningKeys.AddScopedSigner(scope)
   153  
   154  	// we sign
   155  	token, err := p.claim.Encode(p.signerKP)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	// if the signer is not allowed, the store will reject
   161  	rs, err := ctx.StoreCtx().Store.StoreClaim([]byte(token))
   162  	if rs != nil {
   163  		r.Add(rs)
   164  	}
   165  	if err != nil {
   166  		r.AddFromError(err)
   167  	}
   168  	if r.HasNoErrors() {
   169  		r.AddOK("edited signing key %q", p.skName)
   170  	}
   171  	return r, nil
   172  }