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, ¶ms) 38 }, 39 } 40 cmd.Flags().StringVarP(¶ms.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 }