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  }