github.com/kbehouse/nsc@v0.0.6/cmd/revokeclearuser.go (about)

     1  /*
     2   * Copyright 2018-2020 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  	"strings"
    21  
    22  	"github.com/kbehouse/nsc/cmd/store"
    23  	"github.com/nats-io/jwt/v2"
    24  	"github.com/nats-io/nkeys"
    25  	"github.com/spf13/cobra"
    26  )
    27  
    28  func CreateClearRevokeUserCmd() *cobra.Command {
    29  	var params ClearRevokeUserParams
    30  	cmd := &cobra.Command{
    31  		Use:          "delete-user",
    32  		Aliases:      []string{"delete_user"},
    33  		Short:        "Remove a user revocation",
    34  		Args:         MaxArgs(0),
    35  		SilenceUsage: true,
    36  		RunE: func(cmd *cobra.Command, args []string) error {
    37  			return RunAction(cmd, args, &params)
    38  		},
    39  	}
    40  	cmd.Flags().StringVarP(&params.user, "name", "n", "", "user name")
    41  	params.userKey.BindFlags("user-public-key", "u", nkeys.PrefixByteUser, cmd)
    42  	params.AccountContextParams.BindFlags(cmd)
    43  
    44  	return cmd
    45  }
    46  
    47  func init() {
    48  	revokeCmd.AddCommand(CreateClearRevokeUserCmd())
    49  }
    50  
    51  // ClearRevokeUserParams hold the info necessary to add a user to the revocation list in an account
    52  type ClearRevokeUserParams struct {
    53  	AccountContextParams
    54  	user    string
    55  	userKey PubKeyParams
    56  	claim   *jwt.AccountClaims
    57  	SignerParams
    58  }
    59  
    60  func (p *ClearRevokeUserParams) SetDefaults(ctx ActionCtx) error {
    61  	if p.userKey.publicKey != "" && p.user != "" {
    62  		return fmt.Errorf("user and user-public-key are mutually exclusive")
    63  	}
    64  	p.userKey.AllowWildcard = true
    65  	p.AccountContextParams.SetDefaults(ctx)
    66  	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
    67  	return nil
    68  }
    69  
    70  func (p *ClearRevokeUserParams) PreInteractive(ctx ActionCtx) error {
    71  	return p.AccountContextParams.Edit(ctx)
    72  }
    73  
    74  func (p *ClearRevokeUserParams) Load(ctx ActionCtx) error {
    75  	var err error
    76  	if err = p.AccountContextParams.Validate(ctx); err != nil {
    77  		return err
    78  	}
    79  
    80  	if p.user != "" {
    81  		entries, err := ListUsers(ctx.StoreCtx().Store, p.AccountContextParams.Name)
    82  		if err != nil {
    83  			return err
    84  		}
    85  
    86  		n := strings.ToLower(p.user)
    87  		for _, e := range entries {
    88  			if e.Err == nil && strings.ToLower(e.Name) == n {
    89  				p.userKey.publicKey = e.Claims.Claims().Subject
    90  				break
    91  			}
    92  		}
    93  		if p.userKey.publicKey == "" {
    94  			return fmt.Errorf("user %q not found", p.user)
    95  		}
    96  	} else if p.user == "" && p.userKey.publicKey == "" && !InteractiveFlag {
    97  		uc, err := ctx.StoreCtx().DefaultUserClaim(p.AccountContextParams.Name)
    98  		if err != nil {
    99  			return err
   100  		}
   101  		p.userKey.publicKey = uc.Subject
   102  	}
   103  
   104  	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
   105  	return err
   106  }
   107  
   108  func buildRevokedPublicKeyChoices(accountName string, ctx ActionCtx) ([]PubKeyChoice, error) {
   109  	var choices []PubKeyChoice
   110  	st := ctx.StoreCtx().Store
   111  	accClaim, err := st.ReadAccountClaim(accountName)
   112  	if err != nil || len(accClaim.Revocations) == 0 {
   113  		return choices, err
   114  	}
   115  
   116  	keyToName := map[string]string{}
   117  	keyToName[jwt.All] = "All Users"
   118  	infos, err := ListUsers(ctx.StoreCtx().Store, accountName)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	for _, i := range infos {
   123  		if i.Err == nil {
   124  			keyToName[i.Claims.Claims().Subject] = i.Name
   125  		}
   126  	}
   127  
   128  	for key := range accClaim.Revocations {
   129  		pkc := PubKeyChoice{}
   130  		pkc.Key = key
   131  		n := keyToName[key]
   132  		if n == "" {
   133  			n = "[Unknown User]"
   134  		}
   135  		pkc.Label = fmt.Sprintf("%s: %s", key, n)
   136  		choices = append(choices, pkc)
   137  	}
   138  	return choices, nil
   139  }
   140  
   141  func (p *ClearRevokeUserParams) PostInteractive(ctx ActionCtx) error {
   142  	choices, err := buildRevokedPublicKeyChoices(p.AccountContextParams.Name, ctx)
   143  	if err != nil || len(choices) == 0 {
   144  		return err
   145  	}
   146  	if err := p.userKey.Select("select revoked user to clear", choices...); err != nil {
   147  		return err
   148  	}
   149  	return p.SignerParams.Edit(ctx)
   150  }
   151  
   152  func (p *ClearRevokeUserParams) Validate(ctx ActionCtx) error {
   153  	if len(p.claim.Revocations) == 0 {
   154  		return fmt.Errorf("no user revocations set in account %s", p.AccountContextParams.Name)
   155  	}
   156  	if p.userKey.publicKey == "" && p.user == "" {
   157  		return fmt.Errorf("user or user-public-key is required")
   158  	}
   159  	if err := p.userKey.Valid(); err != nil {
   160  		return err
   161  	}
   162  	return p.SignerParams.Resolve(ctx)
   163  }
   164  
   165  func (p *ClearRevokeUserParams) Run(ctx ActionCtx) (store.Status, error) {
   166  	if _, ok := p.claim.Revocations[p.userKey.publicKey]; !ok {
   167  		return nil, fmt.Errorf("user with public key %s is not revoked", p.userKey.publicKey)
   168  	}
   169  	p.claim.ClearRevocation(p.userKey.publicKey)
   170  	token, err := p.claim.Encode(p.signerKP)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	r := store.NewDetailedReport(true)
   175  	StoreAccountAndUpdateStatus(ctx, token, r)
   176  	if r.HasNoErrors() {
   177  		if p.userKey.publicKey == jwt.All {
   178  			r.AddOK("deleted all user revocation")
   179  		} else {
   180  			r.AddOK("deleted user revocation for %q", p.userKey.publicKey)
   181  		}
   182  	}
   183  	return r, nil
   184  }