Skip to content

Commit

Permalink
feat: grant specific authz rules
Browse files Browse the repository at this point in the history
  • Loading branch information
atheeshp committed May 10, 2024
1 parent 9ae7ce5 commit eabb609
Show file tree
Hide file tree
Showing 26 changed files with 1,012 additions and 140 deletions.
640 changes: 595 additions & 45 deletions api/cosmos/authz/v1beta1/authz.pulsar.go

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion proto/cosmos/authz/v1beta1/authz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ message Grant {
// doesn't have a time expiration (other conditions in `authorization`
// may apply to invalidate the grant)
google.protobuf.Timestamp expiration = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = true];

// rules are conditions to execute the grant.
bytes rules = 3;
}

// GrantAuthorization extends a grant with both the addresses of the grantee and granter.
Expand Down Expand Up @@ -79,4 +82,9 @@ message GrantQueueItem {
// // Generic authz rules
// message GenericAuthzRules {
// repeated string blocked_messages = 1;
// }
// }

// AuthzRuleKeys is app specific options to the keys
message AuthzRuleKeys {
bytes raw_json = 1;
}
Empty file modified scripts/dep-assert.sh
100755 → 100644
Empty file.
Empty file modified scripts/go-lint-all.bash
100755 → 100644
Empty file.
Empty file modified scripts/go-mod-tidy-all.sh
100755 → 100644
Empty file.
Empty file modified scripts/go-update-dep-all.sh
100755 → 100644
Empty file.
Empty file modified scripts/init-simapp.sh
100755 → 100644
Empty file.
Empty file modified scripts/mockgen.sh
100755 → 100644
Empty file.
Empty file modified scripts/protoc-swagger-gen.sh
100755 → 100644
Empty file.
Empty file modified scripts/protocgen-pulsar.sh
100755 → 100644
Empty file.
Empty file modified scripts/protocgen.sh
100755 → 100644
Empty file.
Empty file modified scripts/validate-gentxs.sh
100755 → 100644
Empty file.
12 changes: 1 addition & 11 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,17 +335,7 @@ func NewSimApp(
app.CircuitKeeper = circuitkeeper.NewKeeper(appCodec, runtime.NewKVStoreService(keys[circuittypes.StoreKey]), authtypes.NewModuleAddress(govtypes.ModuleName).String(), app.AccountKeeper.AddressCodec())
app.BaseApp.SetCircuitBreaker(&app.CircuitKeeper)

options := map[string]map[string]string{
"Send": {
"BlockedAddresses": "cosmos1rnr5jrt4exl0samwj0yegv99jeskl0hsge5zwt,cosmos1rnr5jrt4exl0samwj0yegv99jeskl0hsge5zwt",
"SpendLimit": "1000stake",
},
"Generic": {
"BlockedMessages": "cosmos.bank.v1beta1.MsgDelegate,cosmos.bank.v1beta1.MsgRedelegate",
},
}

app.AuthzKeeper = authzkeeper.NewKeeper(runtime.NewKVStoreService(keys[authzkeeper.StoreKey]), appCodec, app.MsgServiceRouter(), app.AccountKeeper, options)
app.AuthzKeeper = authzkeeper.NewKeeper(runtime.NewKVStoreService(keys[authzkeeper.StoreKey]), appCodec, app.MsgServiceRouter(), app.AccountKeeper)

groupConfig := group.DefaultConfig()
/*
Expand Down
97 changes: 58 additions & 39 deletions x/auth/ante/authz_rules_ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import (
"fmt"
"strings"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authztypes "github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
Expand All @@ -21,44 +24,55 @@ func NewAuthzDecorator(azk AuthzKeeper) AuthzDecorator {

// AuthzDecorator checks the authorization message grants for some rules.
func (azd AuthzDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
}

signers, err := sigTx.GetSigners()
if err != nil {
return ctx, err
}

grantee := signers[0]

msgs := tx.GetMsgs()
for _, msg := range msgs {
// Check if the message is an authorization message
if authzMsg, ok := msg.(*authztypes.MsgGrant); ok {
fmt.Println("coming here", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
if authzMsg, ok := msg.(*authztypes.MsgExec); ok {

rulesKeys, err := azd.azk.GetAuthzRulesKeys(ctx)
if err != nil {
return ctx, err
}

authz, err := authzMsg.GetAuthorization()
msgs, err := authzMsg.GetMessages()
if err != nil {
return ctx, err
}
options := azd.azk.GetAuthzOptions()
fmt.Println("rules", options, err, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")

switch authzConverted := authz.(type) {
case *banktypes.SendAuthorization:
// if err != nil && errors.Is(authztypes.ErrEmptyAuthzRules, err) {
// continue
// }

if sendRules, ok := options["send"]; !ok {
if checkSendAuthzRulesViolated(authzMsg, authzConverted, sendRules) {
return ctx, fmt.Errorf("authz rules are not meeting")

for _, innerMsg := range msgs {
switch innerMsgConverted := innerMsg.(type) {
case *banktypes.MsgSend:
sendRuleKeysInterface, ok := rulesKeys["Send"]
if !ok {
fmt.Println("no rule keys")
continue
}
}

case *authztypes.GenericAuthorization:
// if err != nil && errors.Is(authztypes.ErrEmptyAuthzRules, err) {
// continue
// }
granter, err := azd.azk.AddressCodec().StringToBytes(innerMsgConverted.FromAddress)
if err != nil {
return ctx, err
}

if genericRules, ok := options["generic"]; !ok {
if checkGenericAuthzRules(authzMsg, authzConverted, genericRules) {
return ctx, fmt.Errorf("authz rules are not meeting")
_, rules := azd.azk.GetAuthzWithRules(ctx, grantee, granter, sdk.MsgTypeURL(&banktypes.MsgSend{}))
if rules != nil {
sendRulesKeys := sendRuleKeysInterface.([]string)
if checkSendAuthzRulesViolated(innerMsgConverted, rules, sendRulesKeys) {
return ctx, fmt.Errorf("authz rules are not meeting")
}
}
}

default:
fmt.Println("default case reached here")
}
}
}
Expand All @@ -68,29 +82,34 @@ func (azd AuthzDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool,
}

// checkSendAuthzRulesViolated returns true if the rules are voilated
func checkSendAuthzRulesViolated(msgGrant *authztypes.MsgGrant, authz *banktypes.SendAuthorization, sendAuthzRules map[string]string) bool {
fmt.Printf("\">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\": %v\n", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
fmt.Printf("sendAuthzRules: %v\n", sendAuthzRules)
if blockedAddrsStr, ok := sendAuthzRules["blockedAddresses"]; ok {
blockedAddrs := strings.Split(blockedAddrsStr, ",")
for _, blockedRecipient := range blockedAddrs {
if msgGrant.Grantee == blockedRecipient {
return true
func checkSendAuthzRulesViolated(msg *banktypes.MsgSend, sendAuthzRules map[string]interface{}, sendRulesKeys []string) bool {
for _, key := range sendRulesKeys {

fmt.Printf("\">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\": %v\n", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
fmt.Printf("sendAuthzRules: %v\n", sendAuthzRules)
if blockedAddrsStrInt, ok := sendAuthzRules["AllowRecipients"]; key == "AllowRecipients" && ok {
blockedAddrsStr := blockedAddrsStrInt.(string)
blockedAddrs := strings.Split(blockedAddrsStr, ",")
for _, blockedRecipient := range blockedAddrs {
if msg.ToAddress == blockedRecipient {
return true
}
}
}
}

if spendLimit, ok := sendAuthzRules["spendLimit"]; ok {
if len(spendLimit) > 1 {
if spendLimitInt, ok := sendAuthzRules["SpendLImit"]; key == "SpendLImit" && ok {
spendLimit := spendLimitInt.(string)
limit, err := sdk.ParseCoinsNormalized(spendLimit)
if err != nil {
return true
}
if !limit.IsAllGTE(authz.SpendLimit) {
if !limit.IsAllGTE(msg.Amount) {
return true
}

return true
}
return true

}

return false
Expand Down
4 changes: 4 additions & 0 deletions x/auth/ante/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/authz"
)

// AccountKeeper defines the contract needed for AccountKeeper related APIs.
Expand All @@ -26,4 +27,7 @@ type FeegrantKeeper interface {

type AuthzKeeper interface {
GetAuthzOptions() map[string]map[string]string
GetAuthzRulesKeys(ctx context.Context) (map[string]interface{}, error)
GetAuthzWithRules(ctx context.Context, grantee, granter sdk.AccAddress, msgType string) (authz.Authorization, map[string]interface{})
AddressCodec() address.Codec
}
4 changes: 4 additions & 0 deletions x/authz/authorizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package authz

import (
context "context"
"encoding/json"

"github.com/cosmos/gogoproto/proto"

Expand All @@ -24,6 +25,9 @@ type Authorization interface {
// ValidateBasic does a simple validation check that
// doesn't require access to any other information.
ValidateBasic() error

// GetOptions are, rules defined if any.
GetOptions() json.RawMessage
}

// AcceptResponse instruments the controller of an authz message if the request is accepted
Expand Down
Loading

0 comments on commit eabb609

Please sign in to comment.