Fabric自定义插件的开发-Auth插件开发

说明:链码开发语言是golang,源码分析是基于v1.4.3版本

系列文章
1、Fabric自定义插件的开发-扩展插件的组织方式
2、Fabric自定义插件的开发-Decorator插件开发
3、Fabric自定义插件的开发-Validators插件开发

Auth插件,可以理解为peer的一个前置防火墙,屏蔽掉一些非法的提案。虽然在链码侧也可以对提案做一些校验,但如果能在最初的入口处拒掉非法请求岂不是更好?本文梳理Auth插件的加载和使用方式,以及分享一个样例。

插件加载

读取插件,在自定义的插件中查找NewFilter函数,且函数格式为:func() auth.Filter,即需要返回一个实现了接口core.handlers.auth.Filter的对象,并将该对象存储在插件库对象registry的成员filters中。

函数:func (r *registry) initAuthPlugin(p *plugin.Plugin) {}
位置:core/handlers/library/registry.go:168

core.handlers.auth.Filter接口定义:

type Filter interface {
	peer.EndorserServer
	Init(next peer.EndorserServer)
}

peer.EndorserServer接口提供了一个方法:ProcessProposal(context.Context, *SignedProposal) (*ProposalResponse, error),用于处理client提交的提案。
所以,Auth插件对象需要提供两个方法:Init和ProcessProposal。
Fabric对Filter接口,有三个默认实现:expirationCheckFilter、filter和reset,其中reset用在特殊场景中,本文不分析,而其它两个实现是对所有场景都使用的。
所有的实现,都有一个next接口成员,用于承载下一个过滤器对象,而Init就是对这个next进行赋值。

插件使用

同样,peer的插件库单例registry对象提供了Lookup方法给外部使用,以获取对应的插件。
Auth类型插件,都是单例,对所有通道的所有链码都生效。在peer收到client的提案时,就会依次执行插件的ProcessProposal方法。
peer进程,在加载完所有的Auth插件之后,会调用Auth插件的Init函数,把这些插件对象组成一个链,而最后一个插件对象的next接口成员指向最终的背书对象(core.endorser.Endorser)

函数:func ChainFilters(endorser peer.EndorserServer, filters ...Filter) peer.EndorserServer {}
位置:core/handlers/auth/auth.go:23

即,提案只有经过所有Auth插件校验之后,才会进入最终的背书流程。
而Auth插件的顺序依赖于core.yaml中的配置:

handlers:
    authFilters:
      -
        name: DefaultAuth
      -
        name: ExpirationCheck    # This filter checks identity x509 certificate expiration
插件开发样例

样例功能,识别提案消息头签名证书中的属性是否包含test字段。fabric支持对证书的属性进行扩展,OID是"1.2.3.4.5.6.7.8.1",也可以自行扩展。

package main

import (
	"context"
	"crypto/x509"
	"encoding/pem"
	"github.com/gogo/protobuf/proto"
	"github.com/hyperledger/fabric/common/attrmgr"
	"github.com/hyperledger/fabric/core/handlers/auth"
	"github.com/hyperledger/fabric/protos/msp"
	"github.com/hyperledger/fabric/protos/peer"
	"github.com/hyperledger/fabric/protos/utils"
	"github.com/pkg/errors"
)

// NewFilter creates a new Filter
func NewFilter() auth.Filter {
	return &identityCheck{}
}

type identityCheck struct {
	next peer.EndorserServer
}

// Init initializes the Filter with the next EndorserServer
func (f *identityCheck) Init(next peer.EndorserServer) {
	f.next = next
}

// ProcessProposal processes a signed proposal
func (f *identityCheck) ProcessProposal(ctx context.Context, signedProp *peer.SignedProposal) (*peer.ProposalResponse, error) {
	prop, err := utils.GetProposal(signedProp.ProposalBytes)
	if err != nil {
		return nil, errors.Wrap(err, "failed parsing proposal")
	}

	hdr, err := utils.GetHeader(prop.Header)
	if err != nil {
		return nil, errors.Wrap(err, "failed parsing header")
	}

	sh, err := utils.GetSignatureHeader(hdr.SignatureHeader)
	if err != nil {
		return nil, errors.Wrap(err, "failed parsing signature header")
	}

	sID := &msp.SerializedIdentity{}
	if err := proto.Unmarshal(sh.Creator, sID); err != nil {
		return nil, errors.Wrap(err, "failed parsing creator")
	}

	block, _ := pem.Decode(sID.GetIdBytes())
	if block == nil {
		return nil, errors.New("Expecting a PEM-encoded X509 certificate; PEM block not found")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, errors.Wrap(err, "failed to parse certificate")
	}
	attrs, err := attrmgr.New().GetAttributesFromCert(cert)
	if err != nil {
		return nil, errors.WithMessage(err, "failed to get attributes from the transaction invoker's certificate")
	}

	if _,ok,_ := attrs.Value("test"); !ok {
		return nil, errors.New("Invalid certificate")
	}

	return f.next.ProcessProposal(ctx, signedProp)
}

func main()  {
	
}

插件的编译使用命令 go build -buildmod=plugin,生成so。
因为有依赖fabric源码,所以编译时,需要先clone一份fabric的代码,且在fabric的目录下进行编译,这样就可以直接用fabric项目的vendor了
这里有个限制,如果你的peer是1.4.0版本,那么在编译so时,也必须使用相同版本的fabric源码,否则会导致so加载失败!
多嘴一句,因为插件so和peer是同一个进程空间,所以,你懂得,peer有的数据,这里都可以获取到~
修改core.yaml中配置,使插件生效:

authFilters:
  -
    name: DefaultAuth
  -
    name: ExpirationCheck    # This filter checks identity x509 certificate expiration
  -
    library: /opt/lib/xx.so

使用此插件后,使用普通证书签名的提案就会被peer拒掉,流程并不会走到链码侧。需要在签发签名证书时,增加指定的证书属性。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值