mirror of https://github.com/poanetwork/quorum.git
permissions: converted permissions to a service registered in line with other services at node level
This commit is contained in:
commit
53d580fb6c
|
@ -20,6 +20,9 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/permission"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -167,6 +170,10 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit)
|
utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utils.IsPermissionEnabled(ctx) {
|
||||||
|
RegisterPermissionService(ctx, stack)
|
||||||
|
}
|
||||||
|
|
||||||
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
|
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
|
||||||
shhEnabled := enableWhisper(ctx)
|
shhEnabled := enableWhisper(ctx)
|
||||||
shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
|
shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
|
||||||
|
@ -190,6 +197,28 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
return stack
|
return stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegisterPermissionService(ctx *cli.Context, stack *node.Node) {
|
||||||
|
if err := stack.Register(func(sctx *node.ServiceContext) (node.Service, error) {
|
||||||
|
dataDir := ctx.GlobalString(utils.DataDirFlag.Name)
|
||||||
|
var permissionConfig types.PermissionConfig
|
||||||
|
var err error
|
||||||
|
if permissionConfig, err = permission.ParsePermissionConifg(dataDir); err != nil {
|
||||||
|
utils.Fatalf("loading of permission-config.json failed", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the permissions management service
|
||||||
|
pc, err := permission.NewQuorumPermissionCtrl(stack, &permissionConfig)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to load the permission contracts as given in permissions-config.json %v", err)
|
||||||
|
}
|
||||||
|
log.Info("permission service created")
|
||||||
|
return pc, nil
|
||||||
|
}); err != nil {
|
||||||
|
utils.Fatalf("Failed to register the permission service: %v", err)
|
||||||
|
}
|
||||||
|
log.Info("permission service registered")
|
||||||
|
}
|
||||||
|
|
||||||
// dumpConfig is the dumpconfig command.
|
// dumpConfig is the dumpconfig command.
|
||||||
func dumpConfig(ctx *cli.Context) error {
|
func dumpConfig(ctx *cli.Context) error {
|
||||||
_, cfg := makeConfigNode(ctx)
|
_, cfg := makeConfigNode(ctx)
|
||||||
|
|
|
@ -343,14 +343,10 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
//START - QUORUM permission service
|
//initialize permission as we can create eth client only after the node and RPC are started
|
||||||
go func() {
|
if utils.IsPermissionEnabled(ctx) {
|
||||||
if ctx.GlobalBool(utils.EnableNodePermissionFlag.Name) {
|
permission.StartPermissionService(stack)
|
||||||
if err := permission.StartQuorumPermissionService(ctx, stack); err != nil {
|
}
|
||||||
utils.Fatalf("Failed to start permissions service %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Start auxiliary services if enabled
|
// Start auxiliary services if enabled
|
||||||
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
|
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
|
||||||
|
|
|
@ -20,9 +20,11 @@ package utils
|
||||||
import (
|
import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -63,7 +65,21 @@ func Fatalf(format string, args ...interface{}) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsPermissionEnabled(ctx *cli.Context) bool {
|
||||||
|
if ctx.GlobalBool(EnableNodePermissionFlag.Name) {
|
||||||
|
fileName := "permission-config.json"
|
||||||
|
fullPath := filepath.Join(ctx.GlobalString(DataDirFlag.Name), fileName)
|
||||||
|
if _, err := os.Stat(fullPath); err != nil {
|
||||||
|
log.Warn("permission-config.json file is missing. permission service will be disabled", "err", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func StartNode(stack *node.Node) {
|
func StartNode(stack *node.Node) {
|
||||||
|
|
||||||
if err := stack.Start(); err != nil {
|
if err := stack.Start(); err != nil {
|
||||||
Fatalf("Error starting protocol stack: %v", err)
|
Fatalf("Error starting protocol stack: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,6 @@ type OrgDetailInfo struct {
|
||||||
SubOrgList []string `json:"subOrgList"`
|
SubOrgList []string `json:"subOrgList"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OrgStruct struct {
|
|
||||||
OrgId string
|
|
||||||
Keys []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// permission config for bootstrapping
|
// permission config for bootstrapping
|
||||||
type PermissionConfig struct {
|
type PermissionConfig struct {
|
||||||
UpgrdAddress common.Address
|
UpgrdAddress common.Address
|
||||||
|
@ -178,8 +173,6 @@ var orgAdminRole string
|
||||||
|
|
||||||
const defaultMapLimit = 100
|
const defaultMapLimit = 100
|
||||||
|
|
||||||
//var OrgKeyMap, _ = lru.New(orgKeyMapLimit)
|
|
||||||
|
|
||||||
var OrgInfoMap = NewOrgCache()
|
var OrgInfoMap = NewOrgCache()
|
||||||
var NodeInfoMap = NewNodeCache()
|
var NodeInfoMap = NewNodeCache()
|
||||||
var RoleInfoMap = NewRoleCache()
|
var RoleInfoMap = NewRoleCache()
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 797 KiB |
Binary file not shown.
After Width: | Height: | Size: 340 KiB |
|
@ -35,7 +35,6 @@ import (
|
||||||
istanbulBackend "github.com/ethereum/go-ethereum/consensus/istanbul/backend"
|
istanbulBackend "github.com/ethereum/go-ethereum/consensus/istanbul/backend"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/quorum"
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
@ -335,12 +334,6 @@ func (s *Ethereum) APIs() []rpc.API {
|
||||||
Service: s.netRPCService,
|
Service: s.netRPCService,
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Namespace: "quorumPermission",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: quorum.NewQuorumControlsAPI(s.txPool, s.accountManager),
|
|
||||||
Public: true,
|
|
||||||
},
|
|
||||||
}...)
|
}...)
|
||||||
return apis
|
return apis
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package quorum
|
package permission
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -10,9 +9,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
@ -65,20 +62,9 @@ const (
|
||||||
Inactive
|
Inactive
|
||||||
)
|
)
|
||||||
|
|
||||||
type PermissionContracts struct {
|
|
||||||
PermInterf *pbind.PermInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
// QuorumControlsAPI provides an API to access Quorum's node permission and org key management related services
|
// QuorumControlsAPI provides an API to access Quorum's node permission and org key management related services
|
||||||
type QuorumControlsAPI struct {
|
type QuorumControlsAPI struct {
|
||||||
txPool *core.TxPool
|
permCtrl *PermissionCtrl
|
||||||
ethClnt *ethclient.Client
|
|
||||||
acntMgr *accounts.Manager
|
|
||||||
txOpt *bind.TransactOpts
|
|
||||||
key *ecdsa.PrivateKey
|
|
||||||
permEnabled bool
|
|
||||||
permConfig *types.PermissionConfig
|
|
||||||
permInterf *pbind.PermInterface
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// txArgs holds arguments required for execute functions
|
// txArgs holds arguments required for execute functions
|
||||||
|
@ -152,25 +138,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewQuorumControlsAPI creates a new QuorumControlsAPI to access quorum services
|
// NewQuorumControlsAPI creates a new QuorumControlsAPI to access quorum services
|
||||||
func NewQuorumControlsAPI(tp *core.TxPool, am *accounts.Manager) *QuorumControlsAPI {
|
func NewQuorumControlsAPI(p *PermissionCtrl) *QuorumControlsAPI {
|
||||||
return &QuorumControlsAPI{tp, nil, am, nil, nil, false, nil, nil}
|
return &QuorumControlsAPI{p}
|
||||||
}
|
|
||||||
|
|
||||||
//Init initializes QuorumControlsAPI with eth client, permission contract and org key management control
|
|
||||||
func (q *QuorumControlsAPI) Init(ethClnt *ethclient.Client, key *ecdsa.PrivateKey, apiName string, pconfig *types.PermissionConfig, pc *pbind.PermInterface) error {
|
|
||||||
// check if the interface contract is deployed or not. if not
|
|
||||||
// permissions apis will not work. return error
|
|
||||||
q.ethClnt = ethClnt
|
|
||||||
q.permConfig = pconfig
|
|
||||||
|
|
||||||
if _, err := pbind.NewPermInterface(q.permConfig.InterfAddress, q.ethClnt); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
q.permEnabled = true
|
|
||||||
q.key = key
|
|
||||||
q.permInterf = pc
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *QuorumControlsAPI) OrgList() []types.OrgInfo {
|
func (q *QuorumControlsAPI) OrgList() []types.OrgInfo {
|
||||||
|
@ -215,9 +184,6 @@ func (q *QuorumControlsAPI) GetOrgDetails(orgId string) (types.OrgDetailInfo, er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *QuorumControlsAPI) initOp(txa ethapi.SendTxArgs) (*pbind.PermInterfaceSession, ExecStatus) {
|
func (q *QuorumControlsAPI) initOp(txa ethapi.SendTxArgs) (*pbind.PermInterfaceSession, ExecStatus) {
|
||||||
if !q.permEnabled {
|
|
||||||
return nil, ErrPermissionDisabled
|
|
||||||
}
|
|
||||||
var err error
|
var err error
|
||||||
var w accounts.Wallet
|
var w accounts.Wallet
|
||||||
|
|
||||||
|
@ -511,7 +477,7 @@ func (q *QuorumControlsAPI) UpdateAccountStatus(orgId string, acct common.Addres
|
||||||
// check if the account is network admin
|
// check if the account is network admin
|
||||||
func (q *QuorumControlsAPI) isNetworkAdmin(account common.Address) bool {
|
func (q *QuorumControlsAPI) isNetworkAdmin(account common.Address) bool {
|
||||||
ac := types.AcctInfoMap.GetAccount(account)
|
ac := types.AcctInfoMap.GetAccount(account)
|
||||||
return ac != nil && ac.RoleId == q.permConfig.NwAdminRole
|
return ac != nil && ac.RoleId == q.permCtrl.permConfig.NwAdminRole
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *QuorumControlsAPI) isOrgAdmin(account common.Address, orgId string) (ExecStatus, error) {
|
func (q *QuorumControlsAPI) isOrgAdmin(account common.Address, orgId string) (ExecStatus, error) {
|
||||||
|
@ -626,7 +592,7 @@ func (q *QuorumControlsAPI) valAccountStatusChange(orgId string, account common.
|
||||||
return ErrAccountNotThere, errors.New("account not there")
|
return ErrAccountNotThere, errors.New("account not there")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ac.IsOrgAdmin && (ac.RoleId == q.permConfig.NwAdminRole || ac.RoleId == q.permConfig.OrgAdminRole) && (op == 1 || op == 3) {
|
if ac.IsOrgAdmin && (ac.RoleId == q.permCtrl.permConfig.NwAdminRole || ac.RoleId == q.permCtrl.permConfig.OrgAdminRole) && (op == 1 || op == 3) {
|
||||||
return ErrOpNotAllowed, errors.New("operation not allowed on org admin account")
|
return ErrOpNotAllowed, errors.New("operation not allowed on org admin account")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,7 +622,7 @@ func (q *QuorumControlsAPI) checkOrgAdminExists(orgId, roleId string, account co
|
||||||
if ac.OrgId != orgId {
|
if ac.OrgId != orgId {
|
||||||
return ErrAccountInUse, errors.New("account part of another org")
|
return ErrAccountInUse, errors.New("account part of another org")
|
||||||
}
|
}
|
||||||
if roleId != "" && roleId == q.permConfig.OrgAdminRole && ac.IsOrgAdmin {
|
if roleId != "" && roleId == q.permCtrl.permConfig.OrgAdminRole && ac.IsOrgAdmin {
|
||||||
return ErrAccountOrgAdmin, errors.New("account already org admin for the org")
|
return ErrAccountOrgAdmin, errors.New("account already org admin for the org")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -666,11 +632,11 @@ func (q *QuorumControlsAPI) checkOrgAdminExists(orgId, roleId string, account co
|
||||||
func (q *QuorumControlsAPI) valSubOrgBreadthDepth(porgId string) (ExecStatus, error) {
|
func (q *QuorumControlsAPI) valSubOrgBreadthDepth(porgId string) (ExecStatus, error) {
|
||||||
org := types.OrgInfoMap.GetOrg(porgId)
|
org := types.OrgInfoMap.GetOrg(porgId)
|
||||||
|
|
||||||
if q.permConfig.SubOrgDepth.Cmp(org.Level) == 0 {
|
if q.permCtrl.permConfig.SubOrgDepth.Cmp(org.Level) == 0 {
|
||||||
return ErrMaxDepth, errors.New("max depth for sub orgs reached")
|
return ErrMaxDepth, errors.New("max depth for sub orgs reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.permConfig.SubOrgBreadth.Cmp(big.NewInt(int64(len(org.SubOrgList)))) == 0 {
|
if q.permCtrl.permConfig.SubOrgBreadth.Cmp(big.NewInt(int64(len(org.SubOrgList)))) == 0 {
|
||||||
return ErrMaxBreadth, errors.New("max breadth for sub orgs reached")
|
return ErrMaxBreadth, errors.New("max breadth for sub orgs reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -725,7 +691,7 @@ func (q *QuorumControlsAPI) valAddOrg(args txArgs, pinterf *pbind.PermInterfaceS
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if any previous op is pending approval for network admin
|
// check if any previous op is pending approval for network admin
|
||||||
if q.checkPendingOp(q.permConfig.NwAdminOrg, pinterf) {
|
if q.checkPendingOp(q.permCtrl.permConfig.NwAdminOrg, pinterf) {
|
||||||
return ErrPendingApprovals
|
return ErrPendingApprovals
|
||||||
}
|
}
|
||||||
// check if org already exists
|
// check if org already exists
|
||||||
|
@ -751,7 +717,7 @@ func (q *QuorumControlsAPI) valApproveOrg(args txArgs, pinterf *pbind.PermInterf
|
||||||
return ErrNotNetworkAdmin
|
return ErrNotNetworkAdmin
|
||||||
}
|
}
|
||||||
// check if anything pending approval
|
// check if anything pending approval
|
||||||
if !q.validatePendingOp(q.permConfig.NwAdminOrg, args.orgId, args.url, args.acctId, 1, pinterf) {
|
if !q.validatePendingOp(q.permCtrl.permConfig.NwAdminOrg, args.orgId, args.url, args.acctId, 1, pinterf) {
|
||||||
return ErrNothingToApprove
|
return ErrNothingToApprove
|
||||||
}
|
}
|
||||||
return ExecSuccess
|
return ExecSuccess
|
||||||
|
@ -796,7 +762,7 @@ func (q *QuorumControlsAPI) valUpdateOrgStatus(args txArgs, pinterf *pbind.PermI
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if passed org id is network admin org. update should not be allowed
|
//check if passed org id is network admin org. update should not be allowed
|
||||||
if args.orgId == q.permConfig.NwAdminOrg {
|
if args.orgId == q.permCtrl.permConfig.NwAdminOrg {
|
||||||
return ErrOpNotAllowed
|
return ErrOpNotAllowed
|
||||||
}
|
}
|
||||||
// check if status update can be performed. Org should be approved for suspension
|
// check if status update can be performed. Org should be approved for suspension
|
||||||
|
@ -820,7 +786,7 @@ func (q *QuorumControlsAPI) valApproveOrgStatus(args txArgs, pinterf *pbind.Perm
|
||||||
} else {
|
} else {
|
||||||
return ErrOpNotAllowed
|
return ErrOpNotAllowed
|
||||||
}
|
}
|
||||||
if !q.validatePendingOp(q.permConfig.NwAdminOrg, args.orgId, "", common.Address{}, pendingOp, pinterf) {
|
if !q.validatePendingOp(q.permCtrl.permConfig.NwAdminOrg, args.orgId, "", common.Address{}, pendingOp, pinterf) {
|
||||||
return ErrNothingToApprove
|
return ErrNothingToApprove
|
||||||
}
|
}
|
||||||
return ExecSuccess
|
return ExecSuccess
|
||||||
|
@ -860,7 +826,7 @@ func (q *QuorumControlsAPI) valAssignAdminRole(args txArgs, pinterf *pbind.PermI
|
||||||
return ErrInvalidInput
|
return ErrInvalidInput
|
||||||
}
|
}
|
||||||
// check if caller is network admin
|
// check if caller is network admin
|
||||||
if args.roleId != q.permConfig.OrgAdminRole && args.roleId != q.permConfig.NwAdminRole {
|
if args.roleId != q.permCtrl.permConfig.OrgAdminRole && args.roleId != q.permCtrl.permConfig.NwAdminRole {
|
||||||
return ErrOpNotAllowed
|
return ErrOpNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -892,7 +858,7 @@ func (q *QuorumControlsAPI) valApproveAdminRole(args txArgs, pinterf *pbind.Perm
|
||||||
return ErrInvalidAccount
|
return ErrInvalidAccount
|
||||||
}
|
}
|
||||||
// validate pending op
|
// validate pending op
|
||||||
if !q.validatePendingOp(q.permConfig.NwAdminOrg, ac.OrgId, "", args.acctId, 4, pinterf) {
|
if !q.validatePendingOp(q.permCtrl.permConfig.NwAdminOrg, ac.OrgId, "", args.acctId, 4, pinterf) {
|
||||||
return ErrNothingToApprove
|
return ErrNothingToApprove
|
||||||
}
|
}
|
||||||
return ExecSuccess
|
return ExecSuccess
|
||||||
|
@ -920,7 +886,7 @@ func (q *QuorumControlsAPI) valRemoveRole(args txArgs, pinterf *pbind.PermInterf
|
||||||
}
|
}
|
||||||
|
|
||||||
// admin roles cannot be removed
|
// admin roles cannot be removed
|
||||||
if args.roleId == q.permConfig.OrgAdminRole || args.roleId == q.permConfig.NwAdminRole {
|
if args.roleId == q.permCtrl.permConfig.OrgAdminRole || args.roleId == q.permCtrl.permConfig.NwAdminRole {
|
||||||
return ErrAdminRoles
|
return ErrAdminRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -943,7 +909,7 @@ func (q *QuorumControlsAPI) valAssignRole(args txArgs, pinterf *pbind.PermInterf
|
||||||
if args.acctId == (common.Address{0}) {
|
if args.acctId == (common.Address{0}) {
|
||||||
return ErrInvalidInput
|
return ErrInvalidInput
|
||||||
}
|
}
|
||||||
if args.roleId == q.permConfig.OrgAdminRole || args.roleId == q.permConfig.NwAdminRole {
|
if args.roleId == q.permCtrl.permConfig.OrgAdminRole || args.roleId == q.permCtrl.permConfig.NwAdminRole {
|
||||||
return ErrInvalidRole
|
return ErrInvalidRole
|
||||||
}
|
}
|
||||||
// check if caller is network admin
|
// check if caller is network admin
|
||||||
|
@ -980,7 +946,7 @@ func (q *QuorumControlsAPI) valUpdateAccountStatus(args txArgs, pinterf *pbind.P
|
||||||
// validateAccount validates the account and returns the wallet associated with that for signing the transaction
|
// validateAccount validates the account and returns the wallet associated with that for signing the transaction
|
||||||
func (q *QuorumControlsAPI) validateAccount(from common.Address) (accounts.Wallet, error) {
|
func (q *QuorumControlsAPI) validateAccount(from common.Address) (accounts.Wallet, error) {
|
||||||
acct := accounts.Account{Address: from}
|
acct := accounts.Account{Address: from}
|
||||||
w, err := q.acntMgr.Find(acct)
|
w, err := q.permCtrl.eth.AccountManager().Find(acct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -990,7 +956,7 @@ func (q *QuorumControlsAPI) validateAccount(from common.Address) (accounts.Walle
|
||||||
func (q *QuorumControlsAPI) newPermInterfaceSession(w accounts.Wallet, txa ethapi.SendTxArgs) *pbind.PermInterfaceSession {
|
func (q *QuorumControlsAPI) newPermInterfaceSession(w accounts.Wallet, txa ethapi.SendTxArgs) *pbind.PermInterfaceSession {
|
||||||
frmAcct, transactOpts, gasLimit, gasPrice, nonce := q.getTxParams(txa, w)
|
frmAcct, transactOpts, gasLimit, gasPrice, nonce := q.getTxParams(txa, w)
|
||||||
ps := &pbind.PermInterfaceSession{
|
ps := &pbind.PermInterfaceSession{
|
||||||
Contract: q.permInterf,
|
Contract: q.permCtrl.permInterf,
|
||||||
CallOpts: bind.CallOpts{
|
CallOpts: bind.CallOpts{
|
||||||
Pending: true,
|
Pending: true,
|
||||||
},
|
},
|
||||||
|
@ -1021,7 +987,7 @@ func (q *QuorumControlsAPI) getTxParams(txa ethapi.SendTxArgs, w accounts.Wallet
|
||||||
if txa.Nonce != nil {
|
if txa.Nonce != nil {
|
||||||
nonce = new(big.Int).SetUint64(uint64(*txa.Nonce))
|
nonce = new(big.Int).SetUint64(uint64(*txa.Nonce))
|
||||||
} else {
|
} else {
|
||||||
nonce = new(big.Int).SetUint64(q.txPool.Nonce(frmAcct.Address))
|
nonce = new(big.Int).SetUint64(q.permCtrl.eth.TxPool().Nonce(frmAcct.Address))
|
||||||
}
|
}
|
||||||
return frmAcct, transactOpts, gasLimit, gasPrice, nonce
|
return frmAcct, transactOpts, gasLimit, gasPrice, nonce
|
||||||
}
|
}
|
|
@ -5,9 +5,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/core/quorum"
|
|
||||||
"github.com/ethereum/go-ethereum/raft"
|
"github.com/ethereum/go-ethereum/raft"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
@ -55,74 +54,23 @@ type PermissionLocalConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PermissionCtrl struct {
|
type PermissionCtrl struct {
|
||||||
node *node.Node
|
node *node.Node
|
||||||
ethClnt *ethclient.Client
|
ethClnt *ethclient.Client
|
||||||
eth *eth.Ethereum
|
eth *eth.Ethereum
|
||||||
permissionedMode bool
|
key *ecdsa.PrivateKey
|
||||||
key *ecdsa.PrivateKey
|
dataDir string
|
||||||
dataDir string
|
permUpgr *pbind.PermUpgr
|
||||||
permUpgr *pbind.PermUpgr
|
permInterf *pbind.PermInterface
|
||||||
permInterf *pbind.PermInterface
|
permNode *pbind.NodeManager
|
||||||
permNode *pbind.NodeManager
|
permAcct *pbind.AcctManager
|
||||||
permAcct *pbind.AcctManager
|
permRole *pbind.RoleManager
|
||||||
permRole *pbind.RoleManager
|
permOrg *pbind.OrgManager
|
||||||
permOrg *pbind.OrgManager
|
permConfig *types.PermissionConfig
|
||||||
permConfig *types.PermissionConfig
|
orgChan chan struct{}
|
||||||
mux sync.Mutex
|
nodeChan chan struct{}
|
||||||
}
|
roleChan chan struct{}
|
||||||
|
acctChan chan struct{}
|
||||||
func (p *PermissionCtrl) Interface() *pbind.PermInterface {
|
mux sync.Mutex
|
||||||
return p.permInterf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts the permission services. services will come up only when
|
|
||||||
// geth is brought up in --permissioned mode and permission-config.json is present
|
|
||||||
func StartQuorumPermissionService(ctx *cli.Context, stack *node.Node) error {
|
|
||||||
|
|
||||||
var quorumApis []string
|
|
||||||
dataDir := ctx.GlobalString(utils.DataDirFlag.Name)
|
|
||||||
|
|
||||||
var permissionConfig types.PermissionConfig
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if permissionConfig, err = ParsePermissionConifg(dataDir); err != nil {
|
|
||||||
log.Error("loading of permission-config.json failed", "error", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// start the permissions management service
|
|
||||||
pc, err := NewQuorumPermissionCtrl(stack, ctx.GlobalBool(utils.EnableNodePermissionFlag.Name), &permissionConfig)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = pc.Start(); err == nil {
|
|
||||||
quorumApis = []string{"quorumPermission"}
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcClient, err := stack.Attach()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
stateReader := ethclient.NewClient(rpcClient)
|
|
||||||
|
|
||||||
for _, apiName := range quorumApis {
|
|
||||||
v := stack.GetRPC(apiName)
|
|
||||||
if v == nil {
|
|
||||||
return errors.New("failed to start quorum permission api")
|
|
||||||
}
|
|
||||||
qapi := v.(*quorum.QuorumControlsAPI)
|
|
||||||
|
|
||||||
err = qapi.Init(stateReader, stack.GetNodeKey(), apiName, &permissionConfig, pc.Interface())
|
|
||||||
if err != nil {
|
|
||||||
log.Info("Failed to starts API", "apiName", apiName)
|
|
||||||
} else {
|
|
||||||
log.Info("API started", "apiName", apiName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// converts local permissions data to global permissions config
|
// converts local permissions data to global permissions config
|
||||||
|
@ -198,74 +146,103 @@ func waitForSync(e *eth.Ethereum) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the controls structure for permissions
|
func StartPermissionService(stack *node.Node) {
|
||||||
func NewQuorumPermissionCtrl(stack *node.Node, permissionedMode bool, pconfig *types.PermissionConfig) (*PermissionCtrl, error) {
|
//initialize permission as we can create eth client only after the node and RPC are started
|
||||||
// Create a new eth client to for interfacing with the contract
|
var permissionService *PermissionCtrl
|
||||||
stateReader, e, err := CreateEthClient(stack)
|
if err := stack.Service(&permissionService); err != nil {
|
||||||
waitForSync(e)
|
utils.Fatalf("cannot access permissions service %v", err)
|
||||||
if err != nil {
|
|
||||||
log.Error("Unable to create ethereum client for permissions check", "err", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
if permissionService == nil {
|
||||||
if pconfig.IsEmpty() && permissionedMode {
|
utils.Fatalf("permission service unavailable")
|
||||||
log.Error("permission-config.json is missing contract address")
|
|
||||||
return nil, errors.New("permission-config.json is missing contract address")
|
|
||||||
}
|
}
|
||||||
pu, err := pbind.NewPermUpgr(pconfig.UpgrdAddress, stateReader)
|
//initialize the service to create eth client and get ethereum service
|
||||||
if err != nil {
|
if err := permissionService.InitializeService(); err != nil {
|
||||||
log.Error("Permissions not enabled for the network", "err", err)
|
utils.Fatalf("permissions service initialization failed %v", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
// check if permissioning contract is there at address. If not return from here
|
if err := permissionService.Start(stack.Server()); err != nil {
|
||||||
pm, err := pbind.NewPermInterface(pconfig.InterfAddress, stateReader)
|
utils.Fatalf("permissions service start failed %v", err)
|
||||||
if err != nil {
|
|
||||||
log.Error("Permissions not enabled for the network", "err", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pmAcct, err := pbind.NewAcctManager(pconfig.AccountAddress, stateReader)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Permissions not enabled for the network", "err", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pmNode, err := pbind.NewNodeManager(pconfig.NodeAddress, stateReader)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Permissions not enabled for the network", "err", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pmRole, err := pbind.NewRoleManager(pconfig.RoleAddress, stateReader)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Permissions not enabled for the network", "err", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pmOrg, err := pbind.NewOrgManager(pconfig.OrgAddress, stateReader)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Permissions not enabled for the network", "err", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &PermissionCtrl{
|
|
||||||
node: stack,
|
|
||||||
ethClnt: stateReader,
|
|
||||||
eth: e,
|
|
||||||
permissionedMode: permissionedMode,
|
|
||||||
key: stack.GetNodeKey(),
|
|
||||||
dataDir: stack.DataDir(),
|
|
||||||
permUpgr: pu,
|
|
||||||
permInterf: pm,
|
|
||||||
permNode: pmNode,
|
|
||||||
permAcct: pmAcct,
|
|
||||||
permRole: pmRole,
|
|
||||||
permOrg: pmOrg,
|
|
||||||
permConfig: pconfig,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts monitoring service for permissions events at contract level
|
// Creates the controls structure for permissions
|
||||||
func (p *PermissionCtrl) Start() error {
|
func NewQuorumPermissionCtrl(stack *node.Node, pconfig *types.PermissionConfig) (*PermissionCtrl, error) {
|
||||||
|
// Create a new ethclient to for interfacing with the contract
|
||||||
|
return &PermissionCtrl{stack, nil, nil, stack.GetNodeKey(), stack.DataDir(), nil, nil, nil, nil, nil, nil, pconfig, make(chan struct{}), make(chan struct{}), make(chan struct{}), make(chan struct{}), sync.Mutex{}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PermissionCtrl) InitializeService() error {
|
||||||
|
clnt, ethereum, err := CreateEthClient(p.node)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("creating eth client failed")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
waitFor
|
||||||
|
Sync(ethereum)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to create ethereum client for permissions check", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.permConfig.IsEmpty() {
|
||||||
|
log.Error("permission-config.json is missing contract address")
|
||||||
|
return errors.New("permission-config.json is missing contract address")
|
||||||
|
}
|
||||||
|
pu, err := pbind.NewPermUpgr(p.permConfig.UpgrdAddress, clnt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Permissions not enabled for the network", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// check if permissioning contract is there at address. If not return from here
|
||||||
|
pm, err := pbind.NewPermInterface(p.permConfig.InterfAddress, clnt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Permissions not enabled for the network", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pmAcct, err := pbind.NewAcctManager(p.permConfig.AccountAddress, clnt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Permissions not enabled for the network", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pmNode, err := pbind.NewNodeManager(p.permConfig.NodeAddress, clnt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Permissions not enabled for the network", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pmRole, err := pbind.NewRoleManager(p.permConfig.RoleAddress, clnt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Permissions not enabled for the network", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pmOrg, err := pbind.NewOrgManager(p.permConfig.OrgAddress, clnt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Permissions not enabled for the network", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.permUpgr = pu
|
||||||
|
p.permInterf = pm
|
||||||
|
p.permAcct = pmAcct
|
||||||
|
p.permNode = pmNode
|
||||||
|
p.permRole = pmRole
|
||||||
|
p.permOrg = pmOrg
|
||||||
|
p.ethClnt = clnt
|
||||||
|
p.eth = ethereum
|
||||||
|
log.Info("permission service initalized")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts the node permissioning and event monitoring for permissions
|
||||||
|
// smart contracts
|
||||||
|
func (p *PermissionCtrl) Start(srvr *p2p.Server) error {
|
||||||
|
|
||||||
|
if p.ethClnt == nil || p.eth == nil {
|
||||||
|
log.Info("permission service not initialized")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Info("permission service start...")
|
||||||
// Permissions initialization
|
// Permissions initialization
|
||||||
if err := p.init(); err != nil {
|
if err := p.init(); err != nil {
|
||||||
log.Error("Permissions init failed", "err", err)
|
log.Error("Permissions init failed", "err", err)
|
||||||
|
@ -283,7 +260,36 @@ func (p *PermissionCtrl) Start() error {
|
||||||
|
|
||||||
// monitor org level account management events
|
// monitor org level account management events
|
||||||
go p.manageAccountPermissions()
|
go p.manageAccountPermissions()
|
||||||
|
log.Info("permission service started")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PermissionCtrl) APIs() []rpc.API {
|
||||||
|
log.Info("permission rpc API called")
|
||||||
|
return []rpc.API{
|
||||||
|
{
|
||||||
|
Namespace: "quorumPermission",
|
||||||
|
Version: "1.0",
|
||||||
|
Service: NewQuorumControlsAPI(s),
|
||||||
|
Public: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PermissionCtrl) Protocols() []p2p.Protocol {
|
||||||
|
return []p2p.Protocol{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PermissionCtrl) Stop() error {
|
||||||
|
if p.eth == nil || p.ethClnt == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Info("stopping permission service...")
|
||||||
|
p.roleChan <- struct{}{}
|
||||||
|
p.orgChan <- struct{}{}
|
||||||
|
p.acctChan <- struct{}{}
|
||||||
|
p.nodeChan <- struct{}{}
|
||||||
|
log.Info("stopped permission service")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,6 +353,9 @@ func (p *PermissionCtrl) manageOrgPermissions() {
|
||||||
|
|
||||||
case evtOrgReactivated = <-chOrgReactivated:
|
case evtOrgReactivated = <-chOrgReactivated:
|
||||||
types.OrgInfoMap.UpsertOrg(evtOrgReactivated.OrgId, evtOrgReactivated.PorgId, evtOrgReactivated.UltParent, evtOrgReactivated.Level, types.OrgApproved)
|
types.OrgInfoMap.UpsertOrg(evtOrgReactivated.OrgId, evtOrgReactivated.PorgId, evtOrgReactivated.UltParent, evtOrgReactivated.Level, types.OrgApproved)
|
||||||
|
case <-p.orgChan:
|
||||||
|
log.Info("quit org contract watch")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,6 +418,9 @@ func (p *PermissionCtrl) manageNodePermissions() {
|
||||||
p.updatePermissionedNodes(evtNodeBlacklisted.EnodeId, NodeDelete)
|
p.updatePermissionedNodes(evtNodeBlacklisted.EnodeId, NodeDelete)
|
||||||
p.updateDisallowedNodes(evtNodeBlacklisted.EnodeId)
|
p.updateDisallowedNodes(evtNodeBlacklisted.EnodeId)
|
||||||
types.NodeInfoMap.UpsertNode(evtNodeBlacklisted.OrgId, evtNodeBlacklisted.EnodeId, types.NodeBlackListed)
|
types.NodeInfoMap.UpsertNode(evtNodeBlacklisted.OrgId, evtNodeBlacklisted.EnodeId, types.NodeBlackListed)
|
||||||
|
case <-p.nodeChan:
|
||||||
|
log.Info("quit node contract watch")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -547,6 +559,9 @@ func (p *PermissionCtrl) manageAccountPermissions() {
|
||||||
case evtStatusChanged = <-chStatusChanged:
|
case evtStatusChanged = <-chStatusChanged:
|
||||||
ac := types.AcctInfoMap.GetAccount(evtStatusChanged.Account)
|
ac := types.AcctInfoMap.GetAccount(evtStatusChanged.Account)
|
||||||
types.AcctInfoMap.UpsertAccount(evtStatusChanged.OrgId, ac.RoleId, evtStatusChanged.Account, ac.IsOrgAdmin, types.AcctStatus(int(evtStatusChanged.Status.Uint64())))
|
types.AcctInfoMap.UpsertAccount(evtStatusChanged.OrgId, ac.RoleId, evtStatusChanged.Account, ac.IsOrgAdmin, types.AcctStatus(int(evtStatusChanged.Status.Uint64())))
|
||||||
|
case <-p.acctChan:
|
||||||
|
log.Info("quit account contract watch")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -829,6 +844,9 @@ func (p *PermissionCtrl) manageRolePermissions() {
|
||||||
} else {
|
} else {
|
||||||
log.Error("Revoke role - cache is missing role", "org", evtRoleRevoked.OrgId, "role", evtRoleRevoked.RoleId)
|
log.Error("Revoke role - cache is missing role", "org", evtRoleRevoked.OrgId, "role", evtRoleRevoked.RoleId)
|
||||||
}
|
}
|
||||||
|
case <-p.roleChan:
|
||||||
|
log.Info("quit role contract watch")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue