github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/revokeactivation_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 "testing" 20 "time" 21 22 "github.com/nats-io/jwt/v2" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestRevokeActivation(t *testing.T) { 27 ts := NewTestStore(t, "revoke_clear_user") 28 defer ts.Done(t) 29 30 ts.AddAccount(t, "A") 31 ts.AddExport(t, "A", jwt.Stream, "foo.>", 0, false) 32 ts.AddExport(t, "A", jwt.Service, "bar", 0, false) 33 ts.AddExport(t, "A", jwt.Service, "public", 0, true) // we support revoking public exports 34 35 _, pub, _ := CreateAccountKey(t) 36 37 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "--subject", "foo.bar", "--target-account", pub) 38 require.NoError(t, err) 39 40 _, _, err = ExecuteCmd(createRevokeActivationCmd(), "--subject", "bar", "--target-account", pub, "--service") 41 require.NoError(t, err) 42 43 _, _, err = ExecuteCmd(createRevokeActivationCmd(), "--subject", "public", "--target-account", pub, "--service") 44 require.NoError(t, err) 45 46 ac, err := ts.Store.ReadAccountClaim("A") 47 require.NoError(t, err) 48 require.Len(t, ac.Exports, 3) 49 50 for _, exp := range ac.Exports { 51 require.True(t, exp.Revocations.IsRevoked(pub, time.Unix(0, 0))) 52 } 53 } 54 55 func TestRevokeActivationAt(t *testing.T) { 56 ts := NewTestStore(t, "test") 57 defer ts.Done(t) 58 59 ts.AddAccount(t, "A") 60 ts.AddExport(t, "A", jwt.Stream, "foo.>", 0, false) 61 ts.AddExport(t, "A", jwt.Service, "bar", 0, false) 62 63 _, pub, _ := CreateAccountKey(t) 64 65 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "--subject", "foo.bar", "--target-account", pub, "--at", "1000") 66 require.NoError(t, err) 67 68 _, _, err = ExecuteCmd(createRevokeActivationCmd(), "--subject", "bar", "--target-account", pub, "--service", "--at", "1000") 69 require.NoError(t, err) 70 71 ac, err := ts.Store.ReadAccountClaim("A") 72 require.NoError(t, err) 73 require.Len(t, ac.Exports, 2) 74 75 for _, exp := range ac.Exports { 76 require.True(t, exp.Revocations.IsRevoked(pub, time.Unix(999, 0))) 77 require.False(t, exp.Revocations.IsRevoked(pub, time.Unix(1001, 0))) 78 } 79 } 80 81 func TestRevokeActivationForStreamInteractive(t *testing.T) { 82 ts := NewTestStore(t, "test") 83 defer ts.Done(t) 84 85 ts.AddAccount(t, "A") 86 ts.AddExport(t, "A", jwt.Stream, "foo.>", 0, false) 87 ts.AddExport(t, "A", jwt.Service, "bar", 0, false) 88 ts.AddAccount(t, "B") 89 ts.AddExport(t, "B", jwt.Stream, "foo.>", 0, false) 90 ts.AddExport(t, "B", jwt.Service, "bar", 0, false) 91 92 _, pub, _ := CreateAccountKey(t) 93 94 input := []interface{}{1, false, 0, pub, "1000"} // second account "B" 95 cmd := createRevokeActivationCmd() 96 HoistRootFlags(cmd) 97 _, _, err := ExecuteInteractiveCmd(cmd, input, "-i") 98 require.NoError(t, err) 99 100 ac, err := ts.Store.ReadAccountClaim("A") 101 require.NoError(t, err) 102 103 for _, exp := range ac.Exports { 104 require.Len(t, exp.Revocations, 0) 105 } 106 107 ac, err = ts.Store.ReadAccountClaim("B") 108 require.NoError(t, err) 109 110 for _, exp := range ac.Exports { 111 if exp.Subject != "foo.>" { 112 require.Len(t, exp.Revocations, 0) 113 continue 114 } 115 require.Len(t, exp.Revocations, 1) 116 require.True(t, exp.Revocations.IsRevoked(pub, time.Unix(999, 0))) 117 require.False(t, exp.Revocations.IsRevoked(pub, time.Unix(1001, 0))) 118 } 119 } 120 121 func TestRevokeActivationForServiceInteractive(t *testing.T) { 122 ts := NewTestStore(t, "test") 123 defer ts.Done(t) 124 125 ts.AddAccount(t, "A") 126 ts.AddExport(t, "A", jwt.Stream, "foo.>", 0, false) 127 ts.AddExport(t, "A", jwt.Service, "bar", 0, false) 128 ts.AddAccount(t, "B") 129 ts.AddExport(t, "B", jwt.Stream, "foo.>", 0, false) 130 ts.AddExport(t, "B", jwt.Service, "bar", 0, false) 131 132 _, pub, _ := CreateAccountKey(t) 133 134 input := []interface{}{1, true, 0, pub, "1000"} // second account "B" 135 cmd := createRevokeActivationCmd() 136 HoistRootFlags(cmd) 137 _, _, err := ExecuteInteractiveCmd(cmd, input, "-i") 138 require.NoError(t, err) 139 140 ac, err := ts.Store.ReadAccountClaim("A") 141 require.NoError(t, err) 142 143 for _, exp := range ac.Exports { 144 require.Len(t, exp.Revocations, 0) 145 } 146 147 ac, err = ts.Store.ReadAccountClaim("B") 148 require.NoError(t, err) 149 150 for _, exp := range ac.Exports { 151 if exp.Subject != "bar" { 152 require.Len(t, exp.Revocations, 0) 153 continue 154 } 155 require.Len(t, exp.Revocations, 1) 156 require.True(t, exp.Revocations.IsRevoked(pub, time.Unix(999, 0))) 157 require.False(t, exp.Revocations.IsRevoked(pub, time.Unix(1001, 0))) 158 } 159 } 160 161 func TestRevokeActivationNoExports(t *testing.T) { 162 ts := NewTestStore(t, "O") 163 defer ts.Done(t) 164 ts.AddAccount(t, "A") 165 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*") 166 require.Error(t, err) 167 require.Contains(t, err.Error(), "doesn't have exports") 168 } 169 170 func TestRevokeActivationServiceNoExports(t *testing.T) { 171 ts := NewTestStore(t, "O") 172 defer ts.Done(t) 173 ts.AddAccount(t, "A") 174 ts.AddExport(t, "A", jwt.Service, "q", 0, false) 175 176 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*") 177 require.Error(t, err) 178 require.Contains(t, err.Error(), "doesn't have stream exports") 179 } 180 181 func TestRevokeActivationStreamNoExports(t *testing.T) { 182 ts := NewTestStore(t, "O") 183 defer ts.Done(t) 184 ts.AddAccount(t, "A") 185 ts.AddExport(t, "A", jwt.Stream, "q", 0, false) 186 187 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service") 188 require.Error(t, err) 189 require.Contains(t, err.Error(), "doesn't have service exports") 190 } 191 192 func TestRevokeActivationSubjectRequired(t *testing.T) { 193 ts := NewTestStore(t, "O") 194 defer ts.Done(t) 195 ts.AddAccount(t, "A") 196 ts.AddExport(t, "A", jwt.Service, "q", 0, false) 197 ts.AddExport(t, "A", jwt.Service, "qq", 0, false) 198 199 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service") 200 require.Error(t, err) 201 require.Contains(t, err.Error(), "a subject is required") 202 } 203 204 func TestRevokeActivationExportNotFound(t *testing.T) { 205 ts := NewTestStore(t, "O") 206 defer ts.Done(t) 207 ts.AddAccount(t, "A") 208 ts.AddExport(t, "A", jwt.Service, "q", 0, false) 209 210 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service", "--subject", "foo") 211 require.Error(t, err) 212 require.Contains(t, err.Error(), "unable to locate export") 213 } 214 215 func TestRevokeActivationDefaultSubject(t *testing.T) { 216 ts := NewTestStore(t, "O") 217 defer ts.Done(t) 218 ts.AddAccount(t, "A") 219 ts.AddExport(t, "A", jwt.Service, "q", 0, false) 220 221 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service") 222 require.NoError(t, err) 223 } 224 225 func TestRevokeActivationAll(t *testing.T) { 226 ts := NewTestStore(t, "O") 227 defer ts.Done(t) 228 ts.AddAccount(t, "A") 229 ts.AddExport(t, "A", jwt.Service, "q", 0, false) 230 231 _, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service", "--subject", "q") 232 require.NoError(t, err) 233 } 234 235 func TestRevokeActivationBadInteractiveAt(t *testing.T) { 236 ts := NewTestStore(t, "O") 237 defer ts.Done(t) 238 ts.AddAccount(t, "A") 239 ts.AddExport(t, "A", jwt.Service, "q", 0, false) 240 241 input := []interface{}{true, 0, "*", "hello"} 242 _, _, err := ExecuteInteractiveCmd(createRevokeActivationCmd(), input) 243 require.Error(t, err) 244 require.Contains(t, err.Error(), `provided value "hello" is not`) 245 }