storj/pkg/macaroon/apikey_test.go
Jeff Wendling 15e74c8c3d uplink share subcommand (#1924)
* cmd/uplink: add share command to restrict an api key

This commit is an early bit of work to just implement restricting
macaroon api keys from the command line. It does not convert
api keys to be macaroons in general.

It also does not apply the path restriction caveats appropriately
yet because it does not encrypt them.

* cmd/uplink: fix path encryption for shares

It should now properly encrypt the path prefixes when adding
caveats to a macaroon.

* fix up linting problems

* print summary of caveat and require iso8601

* make clone part more clear
2019-05-14 12:15:12 -06:00

140 lines
3.6 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package macaroon
import (
"bytes"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/zeebo/errs"
)
func TestSerializeParseRestrictAndCheck(t *testing.T) {
secret, err := NewSecret()
require.NoError(t, err)
key, err := NewAPIKey(secret)
require.NoError(t, err)
serialized := key.Serialize()
parsedKey, err := ParseAPIKey(serialized)
require.NoError(t, err)
require.True(t, bytes.Equal(key.Head(), parsedKey.Head()))
require.True(t, bytes.Equal(key.Tail(), parsedKey.Tail()))
restricted, err := key.Restrict(Caveat{
AllowedPaths: []*Caveat_Path{{
Bucket: []byte("a-test-bucket"),
EncryptedPathPrefix: []byte("a-test-path"),
}},
})
require.NoError(t, err)
serialized = restricted.Serialize()
parsedKey, err = ParseAPIKey(serialized)
require.NoError(t, err)
require.True(t, bytes.Equal(key.Head(), parsedKey.Head()))
require.False(t, bytes.Equal(key.Tail(), parsedKey.Tail()))
now := time.Now()
action1 := Action{
Op: ActionRead,
Time: now,
Bucket: []byte("a-test-bucket"),
EncryptedPath: []byte("a-test-path"),
}
action2 := Action{
Op: ActionRead,
Time: now,
Bucket: []byte("another-test-bucket"),
EncryptedPath: []byte("another-test-path"),
}
require.NoError(t, key.Check(secret, action1, nil))
require.NoError(t, key.Check(secret, action2, nil))
require.NoError(t, parsedKey.Check(secret, action1, nil))
err = parsedKey.Check(secret, action2, nil)
require.True(t, ErrUnauthorized.Has(err), err)
}
func TestRevocation(t *testing.T) {
secret, err := NewSecret()
require.NoError(t, err)
key, err := NewAPIKey(secret)
require.NoError(t, err)
restricted, err := key.Restrict(Caveat{
DisallowReads: true,
})
require.NoError(t, err)
now := time.Now()
action := Action{
Op: ActionWrite,
Time: now,
}
require.NoError(t, key.Check(secret, action, nil))
require.NoError(t, restricted.Check(secret, action, nil))
require.True(t, ErrRevoked.Has(key.Check(secret, action, [][]byte{restricted.Head()})))
require.True(t, ErrRevoked.Has(restricted.Check(secret, action, [][]byte{restricted.Head()})))
}
func TestExpiration(t *testing.T) {
secret, err := NewSecret()
require.NoError(t, err)
key, err := NewAPIKey(secret)
require.NoError(t, err)
now := time.Now()
minuteAgo := now.Add(-time.Minute)
minuteFromNow := now.Add(time.Minute)
twoMinutesAgo := now.Add(-2 * time.Minute)
twoMinutesFromNow := now.Add(2 * time.Minute)
notBeforeMinuteFromNow, err := key.Restrict(Caveat{
NotBefore: &minuteFromNow,
})
require.NoError(t, err)
notAfterMinuteAgo, err := key.Restrict(Caveat{
NotAfter: &minuteAgo,
})
require.NoError(t, err)
for i, test := range []struct {
keyToTest *APIKey
timestampToTest time.Time
errClass *errs.Class
}{
{key, time.Time{}, &Error},
{notBeforeMinuteFromNow, time.Time{}, &Error},
{notAfterMinuteAgo, time.Time{}, &Error},
{key, now, nil},
{notBeforeMinuteFromNow, now, &ErrUnauthorized},
{notAfterMinuteAgo, now, &ErrUnauthorized},
{key, twoMinutesAgo, nil},
{notBeforeMinuteFromNow, twoMinutesAgo, &ErrUnauthorized},
{notAfterMinuteAgo, twoMinutesAgo, nil},
{key, twoMinutesFromNow, nil},
{notBeforeMinuteFromNow, twoMinutesFromNow, nil},
{notAfterMinuteAgo, twoMinutesFromNow, &ErrUnauthorized},
} {
err := test.keyToTest.Check(secret, Action{
Op: ActionRead,
Time: test.timestampToTest,
}, nil)
if test.errClass == nil {
require.NoError(t, err, fmt.Sprintf("test #%d", i+1))
} else {
require.False(t, !test.errClass.Has(err), fmt.Sprintf("test #%d", i+1))
}
}
}