github.com/nats-io/nsc@v0.0.0-20221206222106-35db9400b257/cmd/revokeuser_test.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 "strconv" 20 "testing" 21 "time" 22 23 "github.com/nats-io/jwt" 24 25 "github.com/stretchr/testify/require" 26 ) 27 28 func TestRevokeUser(t *testing.T) { 29 ts := NewTestStore(t, "revoke_clear_user") 30 defer ts.Done(t) 31 32 ts.AddAccount(t, "A") 33 ts.AddUser(t, "A", "one") 34 ts.AddUser(t, "A", "two") 35 ts.AddUser(t, "A", "three") 36 37 _, _, err := ExecuteCmd(createRevokeUserCmd(), "--name", "one") 38 require.NoError(t, err) 39 40 ac, err := ts.Store.ReadAccountClaim("A") 41 require.NoError(t, err) 42 require.Len(t, ac.Revocations, 1) 43 44 u, err := ts.Store.ReadUserClaim("A", "one") 45 require.NoError(t, err) 46 require.True(t, ac.IsClaimRevoked(u)) 47 48 _, _, err = ExecuteCmd(createRevokeUserCmd(), "--name", "two") 49 require.NoError(t, err) 50 51 ac, err = ts.Store.ReadAccountClaim("A") 52 require.NoError(t, err) 53 require.Len(t, ac.Revocations, 2) 54 55 u, err = ts.Store.ReadUserClaim("A", "two") 56 require.NoError(t, err) 57 require.True(t, ac.IsClaimRevoked(u)) 58 59 // Double doesn't do anything 60 _, _, err = ExecuteCmd(createRevokeUserCmd(), "--name", "two") 61 require.NoError(t, err) 62 63 ac, err = ts.Store.ReadAccountClaim("A") 64 require.NoError(t, err) 65 require.Len(t, ac.Revocations, 2) 66 } 67 68 func TestRevokeUserAt(t *testing.T) { 69 ts := NewTestStore(t, "test") 70 defer ts.Done(t) 71 72 ts.AddAccount(t, "A") 73 ts.AddUser(t, "A", "one") 74 ts.AddUser(t, "A", "two") 75 ts.AddUser(t, "A", "three") 76 77 _, _, err := ExecuteCmd(createRevokeUserCmd(), "--name", "one", "--at", "1000") 78 require.NoError(t, err) 79 80 ac, err := ts.Store.ReadAccountClaim("A") 81 require.NoError(t, err) 82 require.Len(t, ac.Revocations, 1) 83 84 u, err := ts.Store.ReadUserClaim("A", "one") 85 require.NoError(t, err) 86 require.False(t, ac.IsClaimRevoked(u)) 87 _, ok := ac.Revocations[u.Subject] 88 require.True(t, ok) 89 90 _, _, err = ExecuteCmd(createRevokeUserCmd(), "--name", "two", "--at", strconv.Itoa(int(time.Now().Unix()))) 91 require.NoError(t, err) 92 93 ac, err = ts.Store.ReadAccountClaim("A") 94 require.NoError(t, err) 95 require.Len(t, ac.Revocations, 2) 96 97 u, err = ts.Store.ReadUserClaim("A", "two") 98 require.NoError(t, err) 99 require.True(t, ac.IsClaimRevoked(u)) 100 _, ok = ac.Revocations[u.Subject] 101 require.True(t, ok) 102 } 103 104 func Test_RevokeUserAccountNameRequired(t *testing.T) { 105 ts := NewTestStore(t, "test") 106 defer ts.Done(t) 107 108 ts.AddAccount(t, "A") 109 ts.AddUser(t, "A", "one") 110 111 ts.AddAccount(t, "B") 112 ts.AddUser(t, "B", "one") 113 114 _, _, err := ExecuteCmd(createRevokeUserCmd(), "--name", "one") 115 require.NoError(t, err) 116 117 ac, err := ts.Store.ReadAccountClaim("B") 118 require.NoError(t, err) 119 require.Len(t, ac.Revocations, 1) 120 121 ac, err = ts.Store.ReadAccountClaim("A") 122 require.NoError(t, err) 123 require.Len(t, ac.Revocations, 0) 124 } 125 126 const keyToRevoke = "UCLMBZ5CBDRDG2TAYOJK23U7IGKPTTW7DTWNOP4TUW4PAB3GRUSKXG3N" 127 128 func TestRevokeUserInteractive(t *testing.T) { 129 ts := NewTestStore(t, "test") 130 defer ts.Done(t) 131 132 ts.AddAccount(t, "A") 133 ts.AddUser(t, "A", "one") 134 ts.AddUser(t, "A", "two") 135 ts.AddAccount(t, "B") 136 ts.AddUser(t, "B", "one") 137 ts.AddUser(t, "B", "two") 138 139 input := []interface{}{0, true, 0, "0"} 140 cmd := createRevokeUserCmd() 141 HoistRootFlags(cmd) 142 _, _, err := ExecuteInteractiveCmd(cmd, input, "-i") 143 require.NoError(t, err) 144 145 ac, err := ts.Store.ReadAccountClaim("A") 146 require.NoError(t, err) 147 require.Len(t, ac.Revocations, 1) 148 149 u, err := ts.Store.ReadUserClaim("A", "one") 150 require.NoError(t, err) 151 require.True(t, ac.IsClaimRevoked(u)) 152 153 cmd = createRevokeUserCmd() 154 HoistRootFlags(cmd) 155 input = []interface{}{0, false, keyToRevoke, "0"} 156 _, _, err = ExecuteInteractiveCmd(cmd, input, "-i") 157 require.NoError(t, err) 158 159 ac, err = ts.Store.ReadAccountClaim("A") 160 require.NoError(t, err) 161 require.True(t, ac.Revocations.IsRevoked(keyToRevoke, time.Unix(0, 0))) 162 require.False(t, ac.Revocations.IsRevoked(keyToRevoke, time.Now().Add(1*time.Hour))) 163 require.Len(t, ac.Revocations, 2) 164 } 165 166 func TestRevokeUserByNkey(t *testing.T) { 167 ts := NewTestStore(t, "test") 168 defer ts.Done(t) 169 170 ts.AddAccount(t, "A") 171 ts.AddUser(t, "A", "one") 172 ts.AddUser(t, "A", "two") 173 174 u, err := ts.Store.ReadUserClaim("A", "one") 175 require.NoError(t, err) 176 177 cmd := createRevokeUserCmd() 178 HoistRootFlags(cmd) 179 _, _, err = ExecuteCmd(cmd, "-u", u.Subject) 180 require.NoError(t, err) 181 _, _, err = ExecuteCmd(cmd, "-u", keyToRevoke) 182 require.NoError(t, err) 183 184 ac, err := ts.Store.ReadAccountClaim("A") 185 require.NoError(t, err) 186 require.Len(t, ac.Revocations, 2) 187 require.True(t, ac.Revocations.IsRevoked(u.Subject, time.Unix(0, 0))) 188 require.True(t, ac.Revocations.IsRevoked(keyToRevoke, time.Unix(0, 0))) 189 190 // make sure one is expired 191 u, err = ts.Store.ReadUserClaim("A", "one") 192 require.NoError(t, err) 193 require.True(t, ac.IsClaimRevoked(u)) 194 // make sure two is not expired 195 u, err = ts.Store.ReadUserClaim("A", "two") 196 require.NoError(t, err) 197 require.False(t, ac.IsClaimRevoked(u)) 198 } 199 200 func TestRevokeUserNameKey(t *testing.T) { 201 ts := NewTestStore(t, "O") 202 defer ts.Done(t) 203 ts.AddAccount(t, "A") 204 _, _, err := ExecuteCmd(createRevokeUserCmd(), "--name", "a", "--user-public-key", "UAUGJSHSTZY4ESHTL32CYYQNGT6MHXDQY6APMFMVRXWZN76RHE2IRN5O") 205 require.Error(t, err) 206 require.Contains(t, err.Error(), "user and user-public-key are mutually exclusive") 207 } 208 209 func TestRevokeUserNameNotFound(t *testing.T) { 210 ts := NewTestStore(t, "O") 211 defer ts.Done(t) 212 ts.AddAccount(t, "A") 213 ts.AddUser(t, "A", "U") 214 _, _, err := ExecuteCmd(createRevokeUserCmd(), "--name", "a") 215 require.Error(t, err) 216 require.Contains(t, err.Error(), "not found") 217 218 _, _, err = ExecuteCmd(createRevokeUserCmd(), "--name", "U") 219 require.NoError(t, err) 220 ac, err := ts.Store.ReadAccountClaim("A") 221 require.NoError(t, err) 222 upk := ts.GetUserPublicKey(t, "A", "U") 223 require.NotEmpty(t, upk) 224 require.Contains(t, ac.Revocations, upk) 225 } 226 227 func TestRevokeDefaultUser(t *testing.T) { 228 ts := NewTestStore(t, "O") 229 defer ts.Done(t) 230 ts.AddAccount(t, "A") 231 ts.AddUser(t, "A", "U") 232 _, _, err := ExecuteCmd(createRevokeUserCmd()) 233 require.NoError(t, err) 234 235 upk := ts.GetUserPublicKey(t, "A", "U") 236 ac, err := ts.Store.ReadAccountClaim("A") 237 require.NoError(t, err) 238 _, ok := ac.Revocations[upk] 239 require.True(t, ok) 240 } 241 242 func TestRevokeUserRequired(t *testing.T) { 243 ts := NewTestStore(t, "O") 244 defer ts.Done(t) 245 ts.AddAccount(t, "A") 246 ts.AddUser(t, "A", "U") 247 ts.AddUser(t, "A", "Y") 248 _, _, err := ExecuteCmd(createRevokeUserCmd()) 249 require.Error(t, err) 250 require.Contains(t, err.Error(), "no default user available") 251 } 252 253 func TestRevokeAllUsers(t *testing.T) { 254 ts := NewTestStore(t, "O") 255 defer ts.Done(t) 256 ts.AddAccount(t, "A") 257 _, _, err := ExecuteCmd(createRevokeUserCmd(), "-u", "*") 258 require.NoError(t, err) 259 260 ac, err := ts.Store.ReadAccountClaim("A") 261 require.NoError(t, err) 262 require.Contains(t, ac.Revocations, jwt.All) 263 } 264 265 func TestRevokeBadUnixTime(t *testing.T) { 266 ts := NewTestStore(t, "O") 267 defer ts.Done(t) 268 ts.AddAccount(t, "A") 269 _, _, err := ExecuteCmd(createRevokeUserCmd(), "-u", "*", "--at", "hello") 270 require.Error(t, err) 271 require.Contains(t, err.Error(), "invalid argument") 272 } 273 274 func TestRevokeRFC3339Time(t *testing.T) { 275 ts := NewTestStore(t, "O") 276 defer ts.Done(t) 277 ts.AddAccount(t, "A") 278 at := time.Now() 279 _, _, err := ExecuteCmd(createRevokeUserCmd(), "-u", "*", "--at", at.Format(time.RFC3339)) 280 require.NoError(t, err) 281 282 c, err := ts.Store.ReadAccountClaim("A") 283 require.NoError(t, err) 284 require.True(t, c.Revocations.IsRevoked("foo", at)) 285 require.False(t, c.Revocations.IsRevoked("foo", at.Add(time.Second))) 286 } 287 288 func TestRevokeBadUnixTimeInteractive(t *testing.T) { 289 ts := NewTestStore(t, "O") 290 defer ts.Done(t) 291 ts.AddAccount(t, "A") 292 input := []interface{}{"*", "hello"} 293 _, _, err := ExecuteInteractiveCmd(createRevokeUserCmd(), input) 294 require.Error(t, err) 295 require.Contains(t, err.Error(), `provided value "hello" is not`) 296 }