Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use CheckAuthorization instead of IsAuthorized #2319

Merged
merged 21 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions testutil/keeper/authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func MockIsAuthorized(m *mock.Mock, address string, policyType types.PolicyType,
m.On("IsAuthorized", mock.Anything, address, policyType).Return(isAuthorized).Once()
}

func MockCheckAuthorization(m *mock.Mock, msg sdk.Msg, isAuthorized error) {
m.On("CheckAuthorization", mock.Anything, msg).Return(isAuthorized).Once()
}

func SetAdminPolices(ctx sdk.Context, ak *keeper.Keeper) string {
admin := sample.AccAddress()
ak.SetPolicies(ctx, types.Policies{Items: []*types.Policy{
Expand Down
18 changes: 18 additions & 0 deletions testutil/keeper/mocks/crosschain/authority.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions testutil/sample/authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sample
import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/zeta-chain/zetacore/pkg/chains"
authoritytypes "github.com/zeta-chain/zetacore/x/authority/types"
)
Expand Down Expand Up @@ -65,3 +66,22 @@ func Authorization() authoritytypes.Authorization {
AuthorizedPolicy: authoritytypes.PolicyType_groupOperational,
}
}

func MultipleSignerMessage() sdk.Msg {
return &TestMessage{}
}

type TestMessage struct{}

var _ sdk.Msg = &TestMessage{}

func (m *TestMessage) Reset() {}
func (m *TestMessage) String() string { return "TestMessage" }
func (m *TestMessage) ProtoMessage() {}
func (m *TestMessage) ValidateBasic() error { return nil }
func (m *TestMessage) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{
sdk.MustAccAddressFromBech32(AccAddress()),
sdk.MustAccAddressFromBech32(AccAddress()),
}
}
47 changes: 47 additions & 0 deletions x/authority/keeper/authorization_list.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package keeper

import (
"fmt"

"cosmossdk.io/errors"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/zeta-chain/zetacore/x/authority/types"
)

// TODO : Refactor this file to authorization_list.go

// SetAuthorizationList sets the authorization list to the store.It returns an error if the list is invalid.
func (k Keeper) SetAuthorizationList(ctx sdk.Context, list types.AuthorizationList) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.AuthorizationListKey))
Expand All @@ -24,3 +29,45 @@ func (k Keeper) GetAuthorizationList(ctx sdk.Context) (val types.AuthorizationLi
k.cdc.MustUnmarshal(b, &val)
return val, true
}

// IsAuthorized checks if the address is authorized for the given policy type
func (k Keeper) IsAuthorized(ctx sdk.Context, address string, policyType types.PolicyType) bool {
policies, found := k.GetPolicies(ctx)
if !found {
return false
}
for _, policy := range policies.Items {
if policy.Address == address && policy.PolicyType == policyType {
return true
}
}
return false
}

// CheckAuthorization checks if the signer is authorized to sign the message
func (k Keeper) CheckAuthorization(ctx sdk.Context, msg sdk.Msg) error {
// Policy transactions must have only one signer
if len(msg.GetSigners()) != 1 {
return errors.Wrap(types.ErrSigners, fmt.Sprintf("msg: %v", sdk.MsgTypeURL(msg)))
}
signer := msg.GetSigners()[0].String()
msgURL := sdk.MsgTypeURL(msg)
authorizationsList, found := k.GetAuthorizationList(ctx)
if !found {
return types.ErrAuthorizationListNotFound
}
policyRequired, err := authorizationsList.GetAuthorizedPolicy(msgURL)
if err != nil {
return errors.Wrap(types.ErrAuthorizationNotFound, fmt.Sprintf("msg: %v", msgURL))
}
//// TODO : check for empty policy
//if policyRequired == types.PolicyType_groupOperational {
// return errors.Wrap(types.ErrMsgNotAuthorized, fmt.Sprintf("msg: %v", sdk.MsgTypeURL(msg)))
//}
policies, found := k.GetPolicies(ctx)
if !found {
return errors.Wrap(types.ErrPoliciesNotFound, fmt.Sprintf("msg: %v", msgURL))
}

return policies.CheckSigner(signer, policyRequired)
}
155 changes: 155 additions & 0 deletions x/authority/keeper/authorization_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package keeper_test
import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types"

keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
Expand Down Expand Up @@ -47,3 +49,156 @@ func TestKeeper_SetAuthorizationList(t *testing.T) {
require.Equal(t, newAuthorizationList, list)
})
}

func TestKeeper_CheckAuthorization(t *testing.T) {
t.Run("successfully check authorization", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
signer := sample.AccAddress()
msg := lightclienttypes.MsgDisableHeaderVerification{
Creator: signer,
}
authorizationList := types.AuthorizationList{Authorizations: []types.Authorization{
{
MsgUrl: sdk.MsgTypeURL(&msg),
AuthorizedPolicy: types.PolicyType_groupOperational,
},
},
}
policies := types.Policies{
Items: []*types.Policy{
{
Address: signer,
PolicyType: types.PolicyType_groupOperational,
},
},
}

k.SetPolicies(ctx, policies)
k.SetAuthorizationList(ctx, authorizationList)

err := k.CheckAuthorization(ctx, &msg)
require.NoError(t, err)
})

t.Run("unable to check authorization with multiple signers", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
signer := sample.AccAddress()
msg := sample.MultipleSignerMessage()
authorizationList := types.AuthorizationList{Authorizations: []types.Authorization{
{
MsgUrl: sdk.MsgTypeURL(msg),
AuthorizedPolicy: types.PolicyType_groupOperational,
},
},
}
policies := types.Policies{
Items: []*types.Policy{
{
Address: signer,
PolicyType: types.PolicyType_groupOperational,
},
},
}
k.SetPolicies(ctx, policies)
k.SetAuthorizationList(ctx, authorizationList)

err := k.CheckAuthorization(ctx, msg)
require.ErrorIs(t, err, types.ErrSigners)
})

t.Run("unable to check authorization with no authorization list", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
signer := sample.AccAddress()
msg := lightclienttypes.MsgDisableHeaderVerification{
Creator: signer,
}

policies := types.Policies{
Items: []*types.Policy{
{
Address: signer,
PolicyType: types.PolicyType_groupOperational,
},
},
}
k.SetPolicies(ctx, policies)

err := k.CheckAuthorization(ctx, &msg)
require.ErrorIs(t, err, types.ErrAuthorizationListNotFound)
})

t.Run("unable to check authorization with no policies", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
signer := sample.AccAddress()
msg := lightclienttypes.MsgDisableHeaderVerification{
Creator: signer,
}
authorizationList := types.AuthorizationList{Authorizations: []types.Authorization{
{
MsgUrl: sdk.MsgTypeURL(&msg),
AuthorizedPolicy: types.PolicyType_groupOperational,
},
},
}
k.SetAuthorizationList(ctx, authorizationList)

err := k.CheckAuthorization(ctx, &msg)
require.ErrorIs(t, err, types.ErrPoliciesNotFound)
})

t.Run("unable to check authorization when the required authorization doesnt exist", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
signer := sample.AccAddress()
msg := lightclienttypes.MsgDisableHeaderVerification{
Creator: signer,
}
authorizationList := types.AuthorizationList{Authorizations: []types.Authorization{
{
MsgUrl: "/zetachain.zetacore.observer.MsgDisableCCTX",
AuthorizedPolicy: types.PolicyType_groupOperational,
},
},
}
policies := types.Policies{
Items: []*types.Policy{
{
Address: signer,
PolicyType: types.PolicyType_groupOperational,
},
},
}
k.SetPolicies(ctx, policies)
k.SetAuthorizationList(ctx, authorizationList)

err := k.CheckAuthorization(ctx, &msg)
require.ErrorIs(t, err, types.ErrAuthorizationNotFound)
})

t.Run("unable to check authorization when check signer fails", func(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)
signer := sample.AccAddress()
msg := lightclienttypes.MsgDisableHeaderVerification{
Creator: signer,
}
authorizationList := types.AuthorizationList{Authorizations: []types.Authorization{
{
MsgUrl: sdk.MsgTypeURL(&msg),
AuthorizedPolicy: types.PolicyType_groupOperational,
},
},
}
policies := types.Policies{
Items: []*types.Policy{
{
Address: signer,
PolicyType: types.PolicyType_groupAdmin,
},
},
}
k.SetPolicies(ctx, policies)
k.SetAuthorizationList(ctx, authorizationList)

err := k.CheckAuthorization(ctx, &msg)
require.ErrorIs(t, err, types.ErrSignerDoesntMatch)
})
}
14 changes: 0 additions & 14 deletions x/authority/keeper/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,3 @@ func (k Keeper) GetPolicies(ctx sdk.Context) (val types.Policies, found bool) {
k.cdc.MustUnmarshal(b, &val)
return val, true
}

// IsAuthorized checks if the address is authorized for the given policy type
func (k Keeper) IsAuthorized(ctx sdk.Context, address string, policyType types.PolicyType) bool {
policies, found := k.GetPolicies(ctx)
if !found {
return false
}
for _, policy := range policies.Items {
if policy.Address == address && policy.PolicyType == policyType {
return true
}
}
return false
}
11 changes: 8 additions & 3 deletions x/authority/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ package types
import errorsmod "cosmossdk.io/errors"

var (
ErrUnauthorized = errorsmod.Register(ModuleName, 1102, "sender not authorized")
ErrInvalidAuthorizationList = errorsmod.Register(ModuleName, 1103, "invalid authorization list")
ErrAuthorizationNotFound = errorsmod.Register(ModuleName, 1104, "authorization not found")
ErrUnauthorized = errorsmod.Register(ModuleName, 1102, "sender not authorized")
ErrInvalidAuthorizationList = errorsmod.Register(ModuleName, 1103, "invalid authorization list")
ErrAuthorizationNotFound = errorsmod.Register(ModuleName, 1104, "authorization not found")
ErrAuthorizationListNotFound = errorsmod.Register(ModuleName, 1105, "authorization list not found")
ErrSigners = errorsmod.Register(ModuleName, 1106, "policy transactions must have only one signer")
ErrMsgNotAuthorized = errorsmod.Register(ModuleName, 1107, "msg type is not authorized")
ErrPoliciesNotFound = errorsmod.Register(ModuleName, 1108, "policies not found")
ErrSignerDoesntMatch = errorsmod.Register(ModuleName, 1109, "signer doesn't match required policy")
)
12 changes: 12 additions & 0 deletions x/authority/types/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package types
import (
"fmt"

"cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand Down Expand Up @@ -55,3 +56,14 @@ func (p Policies) Validate() error {

return nil
}

// CheckSigner checks if the signer is authorized for the given policy type
func (p Policies) CheckSigner(signer string, policyRequired PolicyType) error {
for _, policy := range p.Items {
if policy.Address == signer && policy.PolicyType == policyRequired {
return nil
}
}
return errors.Wrap(ErrSignerDoesntMatch, fmt.Sprintf("signer: %s, policy required for message: %s ",
signer, policyRequired.String()))
}
Loading
Loading