Skip to content

Commit 647f803

Browse files
committed
[FAB-8674] Middleware style authen for cc support
Refactor chaincode support to return the server implementation from its constructor and to wrap it with authentication middleware when TLS is enabled. Change-Id: Id1ab31189d2f0666d7b14924ea8caf0e831897ef Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>
1 parent e9dc2a6 commit 647f803

9 files changed

+54
-111
lines changed

core/chaincode/accesscontrol/access.go

+10-37
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,6 @@ import (
1818

1919
var logger = flogging.MustGetLogger("accessControl")
2020

21-
// Authenticator wraps a chaincode service and authenticates
22-
// chaincode shims (containers)
23-
type Authenticator interface {
24-
// DisableAccessCheck disables the access control
25-
// enforcement of the Authenticator
26-
DisableAccessCheck()
27-
28-
// Generate returns a pair of certificate and private key,
29-
// and associates the hash of the certificate with the given
30-
// chaincode name
31-
Generate(ccName string) (*CertAndPrivKeyPair, error)
32-
33-
// ChaincodeSupportServer - The Authenticator is registered
34-
// as a chaincode service
35-
pb.ChaincodeSupportServer
36-
}
37-
3821
// CertAndPrivKeyPair contains a certificate
3922
// and its corresponding private key in base64 format
4023
type CertAndPrivKeyPair struct {
@@ -44,31 +27,25 @@ type CertAndPrivKeyPair struct {
4427
Key string
4528
}
4629

47-
type authenticator struct {
48-
bypass bool
30+
type Authenticator struct {
4931
mapper *certMapper
50-
pb.ChaincodeSupportServer
5132
}
5233

53-
// NewAuthenticator returns a new authenticator that would wrap the given chaincode service
54-
func NewAuthenticator(srv pb.ChaincodeSupportServer, ca CA) Authenticator {
55-
auth := &authenticator{
56-
mapper: newCertMapper(ca.newClientCertKeyPair),
57-
}
58-
auth.ChaincodeSupportServer = newInterceptor(srv, auth.authenticate)
59-
return auth
34+
func (auth *Authenticator) Wrap(srv pb.ChaincodeSupportServer) pb.ChaincodeSupportServer {
35+
return newInterceptor(srv, auth.authenticate)
6036
}
6137

62-
// DisableAccessCheck disables the access control
63-
// enforcement of the Authenticator
64-
func (ac *authenticator) DisableAccessCheck() {
65-
ac.bypass = true
38+
// NewAuthenticator returns a new authenticator that can wrap a chaincode service
39+
func NewAuthenticator(ca CA) *Authenticator {
40+
return &Authenticator{
41+
mapper: newCertMapper(ca.newClientCertKeyPair),
42+
}
6643
}
6744

6845
// Generate returns a pair of certificate and private key,
6946
// and associates the hash of the certificate with the given
7047
// chaincode name
71-
func (ac *authenticator) Generate(ccName string) (*CertAndPrivKeyPair, error) {
48+
func (ac *Authenticator) Generate(ccName string) (*CertAndPrivKeyPair, error) {
7249
cert, err := ac.mapper.genCert(ccName)
7350
if err != nil {
7451
return nil, err
@@ -79,11 +56,7 @@ func (ac *authenticator) Generate(ccName string) (*CertAndPrivKeyPair, error) {
7956
}, nil
8057
}
8158

82-
func (ac *authenticator) authenticate(msg *pb.ChaincodeMessage, stream grpc.ServerStream) error {
83-
if ac.bypass {
84-
return nil
85-
}
86-
59+
func (ac *Authenticator) authenticate(msg *pb.ChaincodeMessage, stream grpc.ServerStream) error {
8760
if msg.Type != pb.ChaincodeMessage_REGISTER {
8861
logger.Warning("Got message", msg, "but expected a ChaincodeMessage_REGISTER message")
8962
return errors.New("First message needs to be a register")

core/chaincode/accesscontrol/access_test.go

+2-48
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ func TestAccessControl(t *testing.T) {
164164

165165
ca, _ := NewCA()
166166
srv := newCCServer(t, 7052, "example02", true, ca)
167-
auth := NewAuthenticator(srv, ca)
168-
pb.RegisterChaincodeSupportServer(srv.grpcSrv, auth)
167+
auth := NewAuthenticator(ca)
168+
pb.RegisterChaincodeSupportServer(srv.grpcSrv, auth.Wrap(srv))
169169
go srv.grpcSrv.Serve(srv.l)
170170
defer srv.stop()
171171

@@ -290,52 +290,6 @@ func TestAccessControl(t *testing.T) {
290290
logAsserter.assertLastLogContains(t, "with given certificate hash", "not found in registry")
291291
}
292292

293-
func TestAccessControlNoTLS(t *testing.T) {
294-
chaincodeID := &pb.ChaincodeID{Name: "example02"}
295-
payload, err := proto.Marshal(chaincodeID)
296-
registerMsg := &pb.ChaincodeMessage{
297-
Type: pb.ChaincodeMessage_REGISTER,
298-
Payload: payload,
299-
}
300-
putStateMsg := &pb.ChaincodeMessage{
301-
Type: pb.ChaincodeMessage_PUT_STATE,
302-
}
303-
304-
ca, _ := NewCA()
305-
s := newCCServer(t, 8052, "example02", false, ca)
306-
auth := NewAuthenticator(s, ca)
307-
pb.RegisterChaincodeSupportServer(s.grpcSrv, auth)
308-
go s.grpcSrv.Serve(s.l)
309-
defer s.stop()
310-
ctx := context.Background()
311-
ctx, _ = context.WithTimeout(ctx, time.Second)
312-
conn, err := grpc.DialContext(ctx, fmt.Sprintf("localhost:%d", 8052), grpc.WithInsecure(), grpc.WithBlock())
313-
assert.NoError(t, err)
314-
chaincodeSupportClient := pb.NewChaincodeSupportClient(conn)
315-
stream, err := chaincodeSupportClient.Register(context.Background())
316-
stream.Send(registerMsg)
317-
stream.Send(putStateMsg)
318-
// Should fail because we haven't disabled security yet
319-
echoMsg, err := stream.Recv()
320-
assert.Error(t, err)
321-
assert.Contains(t, err.Error(), "TLS is active but chaincode")
322-
assert.Nil(t, echoMsg)
323-
conn.Close()
324-
325-
auth.DisableAccessCheck()
326-
// Now it should work
327-
conn, err = grpc.DialContext(ctx, fmt.Sprintf("localhost:%d", 8052), grpc.WithInsecure(), grpc.WithBlock())
328-
assert.NoError(t, err)
329-
defer conn.Close()
330-
chaincodeSupportClient = pb.NewChaincodeSupportClient(conn)
331-
stream, err = chaincodeSupportClient.Register(context.Background())
332-
stream.Send(registerMsg)
333-
stream.Send(putStateMsg)
334-
echoMsg, err = stream.Recv()
335-
assert.NotNil(t, echoMsg)
336-
assert.NoError(t, err)
337-
}
338-
339293
type logBackend struct {
340294
logEntries chan string
341295
}

core/chaincode/accesscontrol/mapper.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"time"
1414

1515
"github.com/hyperledger/fabric/common/util"
16-
"github.com/spf13/viper"
1716
"golang.org/x/net/context"
1817
"google.golang.org/grpc/credentials"
1918
"google.golang.org/grpc/peer"
@@ -26,14 +25,12 @@ type certHash string
2625
type certMapper struct {
2726
keyGen KeyGenFunc
2827
sync.RWMutex
29-
m map[certHash]string
30-
tls bool
28+
m map[certHash]string
3129
}
3230

3331
func newCertMapper(keyGen KeyGenFunc) *certMapper {
3432
return &certMapper{
3533
keyGen: keyGen,
36-
tls: viper.GetBool("peer.tls.enabled"),
3734
m: make(map[certHash]string),
3835
}
3936
}

core/chaincode/chaincode_support.go

+21-12
Original file line numberDiff line numberDiff line change
@@ -136,30 +136,32 @@ func (chaincodeSupport *ChaincodeSupport) launchStarted(chaincode string) bool {
136136
}
137137

138138
// NewChaincodeSupport creates a new ChaincodeSupport instance
139-
func NewChaincodeSupport(ccEndpoint string, userrunsCC bool, ccstartuptimeout time.Duration, ca accesscontrol.CA) pb.ChaincodeSupportServer {
139+
func NewChaincodeSupport(
140+
ccEndpoint string,
141+
userrunsCC bool,
142+
ccstartuptimeout time.Duration,
143+
caCert []byte,
144+
certGenerator CertGenerator,
145+
) *ChaincodeSupport {
140146
ccprovider.SetChaincodesPath(config.GetPath("peer.fileSystemPath") + string(filepath.Separator) + "chaincodes")
141147
pnid := viper.GetString("peer.networkId")
142148
pid := viper.GetString("peer.id")
143149

144150
theChaincodeSupport = &ChaincodeSupport{
145-
ca: ca,
151+
caCert: caCert,
152+
certGenerator: certGenerator,
146153
runningChaincodes: &runningChaincodes{
147154
chaincodeMap: make(map[string]*chaincodeRTEnv),
148155
launchStarted: make(map[string]bool),
149156
}, peerNetworkID: pnid, peerID: pid,
150157
}
151158

152-
theChaincodeSupport.auth = accesscontrol.NewAuthenticator(theChaincodeSupport, ca)
153159
theChaincodeSupport.peerAddress = ccEndpoint
154160
chaincodeLogger.Infof("Chaincode support using peerAddress: %s\n", theChaincodeSupport.peerAddress)
155161

156162
theChaincodeSupport.userRunsCC = userrunsCC
157163
theChaincodeSupport.ccStartupTimeout = ccstartuptimeout
158-
159164
theChaincodeSupport.peerTLS = viper.GetBool("peer.tls.enabled")
160-
if !theChaincodeSupport.peerTLS {
161-
theChaincodeSupport.auth.DisableAccessCheck()
162-
}
163165

164166
kadef := 0
165167
if ka := viper.GetString("chaincode.keepalive"); ka == "" {
@@ -196,7 +198,7 @@ func NewChaincodeSupport(ccEndpoint string, userrunsCC bool, ccstartuptimeout ti
196198
theChaincodeSupport.shimLogLevel = getLogLevelFromViper("shim")
197199
theChaincodeSupport.logFormat = viper.GetString("chaincode.logging.format")
198200

199-
return theChaincodeSupport.auth
201+
return theChaincodeSupport
200202
}
201203

202204
// getLogLevelFromViper gets the chaincode container log levels from viper
@@ -213,10 +215,17 @@ func getLogLevelFromViper(module string) string {
213215
return levelString
214216
}
215217

218+
// CertGenerator generates client certificates for chaincode.
219+
type CertGenerator interface {
220+
// Generate returns a certificate and private key and associates
221+
// the hash of the certificate with the given chaincode name
222+
Generate(ccName string) (*accesscontrol.CertAndPrivKeyPair, error)
223+
}
224+
216225
// ChaincodeSupport responsible for providing interfacing with chaincodes from the Peer.
217226
type ChaincodeSupport struct {
218-
ca accesscontrol.CA
219-
auth accesscontrol.Authenticator
227+
caCert []byte
228+
certGenerator CertGenerator
220229
runningChaincodes *runningChaincodes
221230
peerAddress string
222231
ccStartupTimeout time.Duration
@@ -358,7 +367,7 @@ func (chaincodeSupport *ChaincodeSupport) getTLSFiles(keyPair *accesscontrol.Cer
358367
return map[string][]byte{
359368
TLSClientKeyPath: []byte(keyPair.Key),
360369
TLSClientCertPath: []byte(keyPair.Cert),
361-
TLSClientRootCertPath: chaincodeSupport.ca.CertBytes(),
370+
TLSClientRootCertPath: chaincodeSupport.caCert,
362371
}
363372
}
364373

@@ -379,7 +388,7 @@ func (chaincodeSupport *ChaincodeSupport) getLaunchConfigs(cccid *ccprovider.CCC
379388
// ----------------------------------------------------------------------------
380389
var certKeyPair *accesscontrol.CertAndPrivKeyPair
381390
if chaincodeSupport.peerTLS {
382-
certKeyPair, err = chaincodeSupport.auth.Generate(cccid.GetCanonicalName())
391+
certKeyPair, err = chaincodeSupport.certGenerator.Generate(cccid.GetCanonicalName())
383392
if err != nil {
384393
return nil, nil, nil, errors.WithMessage(err, fmt.Sprintf("failed generating TLS cert for %s", cccid.GetCanonicalName()))
385394
}

core/chaincode/chaincode_support_test.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ func initMockPeer(chainIDs ...string) error {
164164

165165
ccStartupTimeout := time.Duration(10) * time.Second
166166
ca, _ := accesscontrol.NewCA()
167-
NewChaincodeSupport("0.0.0.0:7052", false, ccStartupTimeout, ca)
167+
certGenerator := accesscontrol.NewAuthenticator(ca)
168+
NewChaincodeSupport("0.0.0.0:7052", false, ccStartupTimeout, ca.CertBytes(), certGenerator)
168169
theChaincodeSupport.executetimeout = time.Duration(1) * time.Second
169170

170171
// Mock policy checker
@@ -815,11 +816,11 @@ func getHistory(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCCom
815816
return nil
816817
}
817818

818-
func getLaunchConfigs(t *testing.T, auth accesscontrol.Authenticator) {
819+
func getLaunchConfigs(t *testing.T, certGenerator CertGenerator) {
819820
newCCSupport := &ChaincodeSupport{peerTLS: true, chaincodeLogLevel: "debug", shimLogLevel: "info"}
820821

821-
//set the authenticator for generating TLS stuff
822-
newCCSupport.auth = auth
822+
//set the certGenerator for generating TLS stuff
823+
newCCSupport.certGenerator = certGenerator
823824

824825
ccContext := ccprovider.NewCCContext("dummyChannelId", "mycc", "v0", "dummyTxid", false, nil, nil)
825826
args, envs, filesToUpload, err := newCCSupport.getLaunchConfigs(ccContext, pb.ChaincodeSpec_GOLANG)
@@ -1169,8 +1170,8 @@ func TestCCFramework(t *testing.T) {
11691170
//call's history result
11701171
getHistory(t, chainID, ccname, ccSide)
11711172

1172-
//just use the previous authhandler for generating TLS key/pair
1173-
getLaunchConfigs(t, theChaincodeSupport.auth)
1173+
//just use the previous certGenerator for generating TLS key/pair
1174+
getLaunchConfigs(t, theChaincodeSupport.certGenerator)
11741175

11751176
ccSide.Quit()
11761177
}

core/chaincode/exectransaction_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ func initPeer(chainIDs ...string) (net.Listener, error) {
100100

101101
ccStartupTimeout := time.Duration(3) * time.Minute
102102
ca, _ := accesscontrol.NewCA()
103-
pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(peerAddress, false, ccStartupTimeout, ca))
103+
certGenerator := accesscontrol.NewAuthenticator(ca)
104+
pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(peerAddress, false, ccStartupTimeout, ca.CertBytes(), certGenerator))
104105

105106
// Mock policy checker
106107
policy.RegisterPolicyCheckerFactory(&mockPolicyCheckerFactory{})

core/chaincode/systemchaincode_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ func initSysCCTests() (*oldSysCCInfo, net.Listener, error) {
6969

7070
ccStartupTimeout := time.Duration(5000) * time.Millisecond
7171
ca, _ := accesscontrol.NewCA()
72-
pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(peerAddress, false, ccStartupTimeout, ca))
72+
certGenerator := accesscontrol.NewAuthenticator(ca)
73+
pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(peerAddress, false, ccStartupTimeout, ca.CertBytes(), certGenerator))
7374

7475
go grpcServer.Serve(lis)
7576

core/scc/cscc/configure_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) {
204204

205205
ccStartupTimeout := time.Duration(30000) * time.Millisecond
206206
ca, _ := accesscontrol.NewCA()
207-
chaincode.NewChaincodeSupport(peerEndpoint, false, ccStartupTimeout, ca)
207+
certGenerator := accesscontrol.NewAuthenticator(ca)
208+
chaincode.NewChaincodeSupport(peerEndpoint, false, ccStartupTimeout, ca.CertBytes(), certGenerator)
208209

209210
// Init the policy checker
210211
policyManagerGetter := &policymocks.MockChannelPolicyManagerGetter{

peer/node/start.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ func computeChaincodeEndpoint(peerHostname string) (ccEndpoint string, err error
502502
func registerChaincodeSupport(grpcServer comm.GRPCServer, ccEndpoint string, ca accesscontrol.CA) {
503503
//get user mode
504504
userRunsCC := chaincode.IsDevMode()
505+
tlsEnabled := viper.GetBool("peer.tls.enabled")
505506

506507
//get chaincode startup timeout
507508
ccStartupTimeout := viper.GetDuration("chaincode.startuptimeout")
@@ -512,7 +513,12 @@ func registerChaincodeSupport(grpcServer comm.GRPCServer, ccEndpoint string, ca
512513
logger.Debugf("Chaincode startup timeout value set to %s", ccStartupTimeout)
513514
}
514515

515-
ccSrv := chaincode.NewChaincodeSupport(ccEndpoint, userRunsCC, ccStartupTimeout, ca)
516+
authenticator := accesscontrol.NewAuthenticator(ca)
517+
chaincodeSupport := chaincode.NewChaincodeSupport(ccEndpoint, userRunsCC, ccStartupTimeout, ca.CertBytes(), authenticator)
518+
ccSrv := pb.ChaincodeSupportServer(chaincodeSupport)
519+
if tlsEnabled {
520+
ccSrv = authenticator.Wrap(ccSrv)
521+
}
516522

517523
//Now that chaincode is initialized, register all system chaincodes.
518524
scc.RegisterSysCCs()

0 commit comments

Comments
 (0)