Skip to content

Commit

Permalink
[FAB-5668] NodeOUs Configuration
Browse files Browse the repository at this point in the history
This change-set does the following:
- It enhance FabricMSPConfig to support Node identification
via OUs.
- Node OUs can be specified in the msp configuration file.
- If the Node OUs check is enabled then only identities
with a recognized Node OU (as setup in the configuration file)
will be considered valid.

Tests have been added to validate the change-set.

Change-Id: If2015dd5ae25c8400f7f2a59b19158002b52e4ba
Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
  • Loading branch information
adecaro committed Oct 20, 2017
1 parent e4cb863 commit 726da6e
Show file tree
Hide file tree
Showing 56 changed files with 1,247 additions and 171 deletions.
83 changes: 81 additions & 2 deletions msp/configbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,39 @@ import (
"gopkg.in/yaml.v2"
)

// OrganizationalUnitIdentifiersConfiguration is used to represent an OU
// and an associated trusted certificate
type OrganizationalUnitIdentifiersConfiguration struct {
Certificate string `yaml:"Certificate,omitempty"`
// Certificate is the path to a root or intermediate certificate
Certificate string `yaml:"Certificate,omitempty"`
// OrganizationalUnitIdentifier is the name of the OU
OrganizationalUnitIdentifier string `yaml:"OrganizationalUnitIdentifier,omitempty"`
}

// NodeOUs contains information on how to tell apart clients, peers and orderers
// based on OUs. If the check is enforced, by setting Enabled to true,
// the MSP will consider an identity valid if it is an identity of a client, a peer or
// an orderer. An identity should have only one of these special OUs.
type NodeOUs struct {
// Enable activates the OU enforcement
Enable bool `yaml:"Enable,omitempty"`
// ClientOUIdentifier specifies how to recognize clients by OU
ClientOUIdentifier *OrganizationalUnitIdentifiersConfiguration `yaml:"ClientOUIdentifier,omitempty"`
// PeerOUIdentifier specifies how to recognize peers by OU
PeerOUIdentifier *OrganizationalUnitIdentifiersConfiguration `yaml:"PeerOUIdentifier,omitempty"`
// OrdererOUIdentifier specifies how to recognize orderers by OU
OrdererOUIdentifier *OrganizationalUnitIdentifiersConfiguration `yaml:"OrdererOUIdentifier,omitempty"`
}

// Configuration represents the accessory configuration an MSP can be equipped with.
// By default, this configuration is stored in a yaml file
type Configuration struct {
// OrganizationalUnitIdentifiers is a list of OUs. If this is set, the MSP
// will consider an identity valid only it contains at least one of these OUs
OrganizationalUnitIdentifiers []*OrganizationalUnitIdentifiersConfiguration `yaml:"OrganizationalUnitIdentifiers,omitempty"`
// NodeOUs enables the MSP to tell apart clients, peers and orderers based
// on the identity's OU.
NodeOUs *NodeOUs `yaml:"NodeOUs,omitempty"`
}

func readFile(file string) ([]byte, error) {
Expand Down Expand Up @@ -204,6 +230,7 @@ func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.M
// if the configuration file is there then load it
// otherwise skip it
var ouis []*msp.FabricOUIdentifier
var nodeOUs *msp.FabricNodeOUs
_, err = os.Stat(configFile)
if err == nil {
// load the file, if there is a failure in loading it then
Expand All @@ -223,17 +250,68 @@ func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.M
if len(configuration.OrganizationalUnitIdentifiers) > 0 {
for _, ouID := range configuration.OrganizationalUnitIdentifiers {
f := filepath.Join(dir, ouID.Certificate)
raw, err = ioutil.ReadFile(f)
raw, err = readFile(f)
if err != nil {
return nil, errors.Wrapf(err, "failed loading OrganizationalUnit certificate at [%s]", f)
}

oui := &msp.FabricOUIdentifier{
Certificate: raw,
OrganizationalUnitIdentifier: ouID.OrganizationalUnitIdentifier,
}
ouis = append(ouis, oui)
}
}

// Prepare NodeOUs
if configuration.NodeOUs != nil && configuration.NodeOUs.Enable {
mspLogger.Info("Loading NodeOUs")
if configuration.NodeOUs.ClientOUIdentifier == nil || len(configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier) == 0 {
return nil, errors.New("Failed loading NodeOUs. ClientOU must be different from nil.")
}
if configuration.NodeOUs.PeerOUIdentifier == nil || len(configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier) == 0 {
return nil, errors.New("Failed loading NodeOUs. PeerOU must be different from nil.")
}
if configuration.NodeOUs.OrdererOUIdentifier == nil || len(configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier) == 0 {
return nil, errors.New("Failed loading NodeOUs. OrdererOU must be different from nil.")
}

nodeOUs = &msp.FabricNodeOUs{
Enable: configuration.NodeOUs.Enable,
ClientOUIdentifier: &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.ClientOUIdentifier.OrganizationalUnitIdentifier},
PeerOUIdentifier: &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.PeerOUIdentifier.OrganizationalUnitIdentifier},
OrdererOUIdentifier: &msp.FabricOUIdentifier{OrganizationalUnitIdentifier: configuration.NodeOUs.OrdererOUIdentifier.OrganizationalUnitIdentifier},
}

// Read certificates, if defined

// ClientOU
f := filepath.Join(dir, configuration.NodeOUs.ClientOUIdentifier.Certificate)
raw, err = readFile(f)
if err != nil {
mspLogger.Infof("Failed loading ClientOU certificate at [%s]: [%s]", f, err)
} else {
nodeOUs.ClientOUIdentifier.Certificate = raw
}

// PeerOU
f = filepath.Join(dir, configuration.NodeOUs.PeerOUIdentifier.Certificate)
raw, err = readFile(f)
if err != nil {
mspLogger.Debugf("Failed loading PeerOU certificate at [%s]: [%s]", f, err)
} else {
nodeOUs.PeerOUIdentifier.Certificate = raw
}

// OrdererOU
f = filepath.Join(dir, configuration.NodeOUs.OrdererOUIdentifier.Certificate)
raw, err = readFile(f)
if err != nil {
mspLogger.Debugf("Failed loading OrdererOU certificate at [%s]: [%s]", f, err)
} else {
nodeOUs.OrdererOUIdentifier.Certificate = raw
}
}
} else {
mspLogger.Debugf("MSP configuration file not found at [%s]: [%s]", configFile, err)
}
Expand All @@ -256,6 +334,7 @@ func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.M
CryptoConfig: cryptoConfig,
TlsRootCerts: tlsCACerts,
TlsIntermediateCerts: tlsIntermediateCerts,
FabricNodeOUs: nodeOUs,
}

fmpsjs, _ := proto.Marshal(fmspconf)
Expand Down
4 changes: 3 additions & 1 deletion msp/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ func New(opts NewOpts) (MSP, error) {
case *BCCSPNewOpts:
switch opts.GetVersion() {
case MSPv1_0:
return newBccspMsp()
return newBccspMsp(MSPv1_0)
case MSPv1_1:
return newBccspMsp(MSPv1_1)
default:
return nil, errors.Errorf("Invalid *BCCSPNewOpts. Version not recognized [%v]", opts.GetVersion())
}
Expand Down
13 changes: 13 additions & 0 deletions msp/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ package msp
import (
"testing"

"reflect"
"runtime"

"github.com/stretchr/testify/assert"
)

Expand All @@ -33,6 +36,16 @@ func TestNew(t *testing.T) {
i, err := New(&BCCSPNewOpts{NewBaseOpts{Version: MSPv1_0}})
assert.NoError(t, err)
assert.NotNil(t, i)
assert.Equal(t, MSPVersion(MSPv1_0), i.(*bccspmsp).version)
assert.Equal(t, runtime.FuncForPC(reflect.ValueOf(i.(*bccspmsp).internalSetupFunc).Pointer()).Name(), "github.com/hyperledger/fabric/msp.(*bccspmsp).(github.com/hyperledger/fabric/msp.setupV1)-fm")
assert.Equal(t, runtime.FuncForPC(reflect.ValueOf(i.(*bccspmsp).internalValidateIdentityOusFunc).Pointer()).Name(), "github.com/hyperledger/fabric/msp.(*bccspmsp).(github.com/hyperledger/fabric/msp.validateIdentityOUsV1)-fm")

i, err = New(&BCCSPNewOpts{NewBaseOpts{Version: MSPv1_1}})
assert.NoError(t, err)
assert.NotNil(t, i)
assert.Equal(t, MSPVersion(MSPv1_1), i.(*bccspmsp).version)
assert.Equal(t, runtime.FuncForPC(reflect.ValueOf(i.(*bccspmsp).internalSetupFunc).Pointer()).Name(), "github.com/hyperledger/fabric/msp.(*bccspmsp).(github.com/hyperledger/fabric/msp.setupV11)-fm")
assert.Equal(t, runtime.FuncForPC(reflect.ValueOf(i.(*bccspmsp).internalValidateIdentityOusFunc).Pointer()).Name(), "github.com/hyperledger/fabric/msp.(*bccspmsp).(github.com/hyperledger/fabric/msp.validateIdentityOUsV11)-fm")

i, err = New(&IdemixNewOpts{NewBaseOpts{Version: MSPv1_0}})
assert.NoError(t, err)
Expand Down
84 changes: 75 additions & 9 deletions msp/msp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func TestMSPSetupNoCryptoConf(t *testing.T) {
b, err := proto.Marshal(mspconf)
assert.NoError(t, err)
conf.Config = b
newmsp, err := newBccspMsp()
newmsp, err := newBccspMsp(MSPv1_0)
assert.NoError(t, err)
err = newmsp.Setup(conf)
assert.NoError(t, err)
Expand All @@ -97,7 +97,7 @@ func TestMSPSetupNoCryptoConf(t *testing.T) {
b, err = proto.Marshal(mspconf)
assert.NoError(t, err)
conf.Config = b
newmsp, err = newBccspMsp()
newmsp, err = newBccspMsp(MSPv1_0)
assert.NoError(t, err)
err = newmsp.Setup(conf)
assert.NoError(t, err)
Expand All @@ -109,7 +109,7 @@ func TestMSPSetupNoCryptoConf(t *testing.T) {
b, err = proto.Marshal(mspconf)
assert.NoError(t, err)
conf.Config = b
newmsp, err = newBccspMsp()
newmsp, err = newBccspMsp(MSPv1_0)
assert.NoError(t, err)
err = newmsp.Setup(conf)
assert.NoError(t, err)
Expand Down Expand Up @@ -157,7 +157,7 @@ func TestNotFoundInBCCSP(t *testing.T) {

assert.NoError(t, err)

thisMSP, err := newBccspMsp()
thisMSP, err := newBccspMsp(MSPv1_0)
assert.NoError(t, err)
ks, err := sw.NewFileBasedKeyStore(nil, filepath.Join(dir, "keystore"), true)
assert.NoError(t, err)
Expand Down Expand Up @@ -208,7 +208,7 @@ func TestGetSigningIdentityFromVerifyingMSP(t *testing.T) {
os.Exit(-1)
}

newmsp, err := newBccspMsp()
newmsp, err := newBccspMsp(MSPv1_0)
assert.NoError(t, err)
err = newmsp.Setup(conf)
assert.NoError(t, err)
Expand Down Expand Up @@ -327,7 +327,7 @@ func TestBadAdminIdentity(t *testing.T) {
conf, err := GetLocalMspConfig("testdata/badadmin", nil, "DEFAULT")
assert.NoError(t, err)

thisMSP, err := newBccspMsp()
thisMSP, err := newBccspMsp(MSPv1_0)
assert.NoError(t, err)
ks, err := sw.NewFileBasedKeyStore(nil, filepath.Join("testdata/badadmin", "keystore"), true)
assert.NoError(t, err)
Expand Down Expand Up @@ -913,13 +913,13 @@ func TestMain(m *testing.M) {
os.Exit(-1)
}

localMsp, err = newBccspMsp()
localMsp, err = newBccspMsp(MSPv1_0)
if err != nil {
fmt.Printf("Constructor for msp should have succeeded, got err %s instead", err)
os.Exit(-1)
}

localMspBad, err = newBccspMsp()
localMspBad, err = newBccspMsp(MSPv1_0)
if err != nil {
fmt.Printf("Constructor for msp should have succeeded, got err %s instead", err)
os.Exit(-1)
Expand Down Expand Up @@ -978,11 +978,77 @@ func getIdentity(t *testing.T, path string) Identity {
return id
}

func getLocalMSPWithError(t *testing.T, dir string) (MSP, error) {
conf, err := GetLocalMspConfig(dir, nil, "DEFAULT")
assert.NoError(t, err)

thisMSP, err := newBccspMsp(MSPv1_0)
assert.NoError(t, err)
ks, err := sw.NewFileBasedKeyStore(nil, filepath.Join(dir, "keystore"), true)
assert.NoError(t, err)
csp, err := sw.New(256, "SHA2", ks)
assert.NoError(t, err)
thisMSP.(*bccspmsp).bccsp = csp

return thisMSP, thisMSP.Setup(conf)
}

func getLocalMSPWithVersionAndError(t *testing.T, dir string, version MSPVersion) (MSP, error) {
conf, err := GetLocalMspConfig(dir, nil, "DEFAULT")
assert.NoError(t, err)

thisMSP, err := newBccspMsp(version)
assert.NoError(t, err)
ks, err := sw.NewFileBasedKeyStore(nil, filepath.Join(dir, "keystore"), true)
assert.NoError(t, err)
csp, err := sw.New(256, "SHA2", ks)
assert.NoError(t, err)
thisMSP.(*bccspmsp).bccsp = csp

return thisMSP, thisMSP.Setup(conf)
}

func getLocalMSP(t *testing.T, dir string) MSP {
conf, err := GetLocalMspConfig(dir, nil, "DEFAULT")
assert.NoError(t, err)

thisMSP, err := newBccspMsp()
thisMSP, err := newBccspMsp(MSPv1_0)
assert.NoError(t, err)
ks, err := sw.NewFileBasedKeyStore(nil, filepath.Join(dir, "keystore"), true)
assert.NoError(t, err)
csp, err := sw.New(256, "SHA2", ks)
assert.NoError(t, err)
thisMSP.(*bccspmsp).bccsp = csp

err = thisMSP.Setup(conf)
assert.NoError(t, err)

return thisMSP
}

func getLocalMSPWithVersion(t *testing.T, dir string, version MSPVersion) MSP {
conf, err := GetLocalMspConfig(dir, nil, "DEFAULT")
assert.NoError(t, err)

thisMSP, err := newBccspMsp(version)
assert.NoError(t, err)
ks, err := sw.NewFileBasedKeyStore(nil, filepath.Join(dir, "keystore"), true)
assert.NoError(t, err)
csp, err := sw.New(256, "SHA2", ks)
assert.NoError(t, err)
thisMSP.(*bccspmsp).bccsp = csp

err = thisMSP.Setup(conf)
assert.NoError(t, err)

return thisMSP
}

func getLocalMSPWithName(t *testing.T, name, dir string) MSP {
conf, err := GetLocalMspConfig(dir, nil, name)
assert.NoError(t, err)

thisMSP, err := newBccspMsp(MSPv1_0)
assert.NoError(t, err)
ks, err := sw.NewFileBasedKeyStore(nil, filepath.Join(dir, "keystore"), true)
assert.NoError(t, err)
Expand Down
Loading

0 comments on commit 726da6e

Please sign in to comment.