github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/bddtests/steps/bootstrap_util.py (about)

     1  # Copyright IBM Corp. 2016 All Rights Reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #      http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  #
    15  
    16  import time
    17  import sys
    18  import hashlib
    19  
    20  if sys.version_info < (3, 6):
    21      import sha3
    22  
    23  from OpenSSL import crypto
    24  from OpenSSL import rand
    25  import ecdsa
    26  
    27  from collections import namedtuple
    28  from itertools import groupby
    29  
    30  from enum import Enum
    31  
    32  from google.protobuf import timestamp_pb2
    33  from common import common_pb2 as common_dot_common_pb2
    34  from common import configtx_pb2 as common_dot_configtx_pb2
    35  from common import configuration_pb2 as common_dot_configuration_pb2
    36  from common import policies_pb2 as common_dot_policies_pb2
    37  from msp import msp_config_pb2, msp_principal_pb2, identities_pb2
    38  from peer import configuration_pb2 as peer_dot_configuration_pb2
    39  from orderer import configuration_pb2 as orderer_dot_configuration_pb2
    40  import orderer_util
    41  
    42  from contexthelper import ContextHelper
    43  
    44  import os
    45  import re
    46  import shutil
    47  import compose
    48  
    49  # Type to represent tuple of user, nodeName, ogranization
    50  NodeAdminTuple = namedtuple("NodeAdminTuple", ['user', 'nodeName', 'organization'])
    51  
    52  
    53  ApplicationGroup = "Application"
    54  OrdererGroup     = "Orderer"
    55  ConsortiumsGroup = "Consortiums"
    56  MSPKey           = "MSP"
    57  toValue = lambda message: message.SerializeToString()
    58  
    59  
    60  class Network(Enum):
    61      Orderer = 1
    62      Peer = 2
    63  
    64  
    65  def GetUUID():
    66      return compose.Composition.GetUUID()
    67  
    68  
    69  def createRSAKey():
    70      # Create RSA key, 2048 bit
    71      pk = crypto.PKey()
    72      pk.generate_key(crypto.TYPE_RSA, 2048)
    73      assert pk.check() == True
    74      return pk
    75  
    76  
    77  def createECDSAKey(curve=ecdsa.NIST256p):
    78      # Create ECDSA key
    79      sk = ecdsa.SigningKey.generate(curve=curve)
    80      return sk
    81  
    82  
    83  def computeCryptoHash(data):
    84      ' This will currently return 128 hex characters'
    85      # s = hashlib.sha3_256()
    86      s = hashlib.sha256()
    87      # s = hashlib.shake_256()
    88      #return s.digest(64)
    89      s.update(data)
    90      return s.digest()
    91  
    92  
    93  def createCertRequest(pkey, digest="sha256", **name):
    94      """
    95      Create a certificate request.
    96      Arguments: pkey   - The key to associate with the request
    97                 digest - Digestion method to use for signing, default is sha256
    98                 **name - The name of the subject of the request, possible
    99                          arguments are:
   100                            C     - Country name
   101                            ST    - State or province name
   102                            L     - Locality name
   103                            O     - Organization name
   104                            OU    - Organizational unit name
   105                            CN    - Common name
   106                            emailAddress - E-mail address
   107      Returns:   The certificate request in an X509Req object
   108      """
   109      req = crypto.X509Req()
   110      subj = req.get_subject()
   111  
   112      for key, value in name.items():
   113          setattr(subj, key, value)
   114  
   115      req.set_pubkey(pkey)
   116      req.sign(pkey, digest)
   117      return req
   118  
   119  
   120  def createCertificate(req, issuerCertKey, serial, validityPeriod, digest="sha256", isCA=False):
   121      """
   122      Generate a certificate given a certificate request.
   123      Arguments: req        - Certificate request to use
   124                 issuerCert - The certificate of the issuer
   125                 issuerKey  - The private key of the issuer
   126                 serial     - Serial number for the certificate
   127                 notBefore  - Timestamp (relative to now) when the certificate
   128                              starts being valid
   129                 notAfter   - Timestamp (relative to now) when the certificate
   130                              stops being valid
   131                 digest     - Digest method to use for signing, default is sha256
   132      Returns:   The signed certificate in an X509 object
   133      """
   134      issuerCert, issuerKey = issuerCertKey
   135      notBefore, notAfter = validityPeriod
   136      cert = crypto.X509()
   137      cert.set_version(3)
   138      cert.set_serial_number(serial)
   139      cert.gmtime_adj_notBefore(notBefore)
   140      cert.gmtime_adj_notAfter(notAfter)
   141      cert.set_issuer(issuerCert.get_subject())
   142      cert.set_subject(req.get_subject())
   143      cert.set_pubkey(req.get_pubkey())
   144      if isCA:
   145          cert.add_extensions([crypto.X509Extension("basicConstraints", True,
   146                                                    "CA:TRUE, pathlen:0"),
   147                               crypto.X509Extension("subjectKeyIdentifier", False, "hash",
   148                                                    subject=cert)])
   149          #TODO: This only is appropriate for root self signed!!!!
   150          cert.add_extensions([crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=cert)])
   151      else:
   152          cert.add_extensions([crypto.X509Extension("basicConstraints", True,
   153                                                    "CA:FALSE"),
   154                               crypto.X509Extension("subjectKeyIdentifier", False, "hash",
   155                                                    subject=cert)])
   156          cert.add_extensions([crypto.X509Extension("authorityKeyIdentifier", False, "keyid:always", issuer=issuerCert)])
   157  
   158      cert.sign(issuerKey, digest)
   159      return cert
   160  
   161  
   162  # SUBJECT_DEFAULT = {countryName : "US", stateOrProvinceName : "NC", localityName : "RTP", organizationName : "IBM", organizationalUnitName : "Blockchain"}
   163  
   164  class Entity:
   165      def __init__(self, name):
   166          self.name = name
   167          # Create a ECDSA key, then a crypto pKey from the DER for usage with cert requests, etc.
   168          self.ecdsaSigningKey = createECDSAKey()
   169          self.rsaSigningKey = createRSAKey()
   170          self.pKey = crypto.load_privatekey(crypto.FILETYPE_ASN1, self.ecdsaSigningKey.to_der())
   171          # Signing related ecdsa config
   172          self.hashfunc = hashlib.sha256
   173          self.sigencode = ecdsa.util.sigencode_der_canonize
   174          self.sigdecode = ecdsa.util.sigdecode_der
   175  
   176      def createCertRequest(self, nodeName):
   177          req = createCertRequest(self.pKey, C="US", ST="North Carolina", L="RTP", O="IBM", CN=nodeName)
   178          # print("request => {0}".format(crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)))
   179          return req
   180  
   181      def createTLSCertRequest(self, nodeName):
   182          req = createCertRequest(self.rsaSigningKey, C="US", ST="North Carolina", L="RTP", O="IBM", CN=nodeName)
   183          # print("request => {0}".format(crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)))
   184          return req
   185  
   186  
   187      def computeHash(self, data):
   188          s = self.hashfunc()
   189          s.update(data)
   190          return s.digest()
   191  
   192      def sign(self, dataAsBytearray):
   193          return self.ecdsaSigningKey.sign(dataAsBytearray, hashfunc=self.hashfunc, sigencode=self.sigencode)
   194  
   195      def verifySignature(self, signature, signersCert, data):
   196          'Will verify the signature of an entity based upon public cert'
   197          vk = ecdsa.VerifyingKey.from_der(crypto.dump_publickey(crypto.FILETYPE_ASN1, signersCert.get_pubkey()))
   198          assert vk.verify(signature, data, hashfunc=self.hashfunc, sigdecode=self.sigdecode), "Invalid signature!!"
   199  
   200      def getPrivateKeyAsPEM(self):
   201          return self.ecdsaSigningKey.to_pem()
   202  
   203  
   204  class User(Entity, orderer_util.UserRegistration):
   205      def __init__(self, name, directory):
   206          Entity.__init__(self, name)
   207          orderer_util.UserRegistration.__init__(self, name, directory)
   208          self.tags = {}
   209  
   210      def setTagValue(self, tagKey, tagValue, overwrite=False):
   211          if tagKey in self.tags:
   212              assert not overwrite,"TagKey '{0}' already exists for user {1}, and did not provide overwrite=True".format(tagKey, self.getUserName())
   213          self.tags[tagKey] = tagValue
   214          return tagValue
   215  
   216      def cleanup(self):
   217          self.closeStreams()
   218  
   219  
   220  class Organization(Entity):
   221  
   222      def __init__(self, name):
   223          Entity.__init__(self, name)
   224          req = createCertRequest(self.pKey, C="US", ST="North Carolina", L="RTP", O="IBM", CN=name)
   225          numYrs = 1
   226          self.signedCert = createCertificate(req, (req, self.pKey), 1000, (0, 60 * 60 * 24 * 365 * numYrs), isCA=True)
   227          # Which networks this organization belongs to
   228          self.networks = []
   229  
   230      def __repr__(self):
   231          return "name:{0}, networks: {1}".format(self.name, self.networks)
   232  
   233      def getSelfSignedCert(self):
   234          return self.signedCert
   235  
   236      def getCertAsPEM(self):
   237          return crypto.dump_certificate(crypto.FILETYPE_PEM, self.getSelfSignedCert())
   238  
   239      def getMSPConfig(self):
   240          certPemsList = [crypto.dump_certificate(crypto.FILETYPE_PEM, self.getSelfSignedCert())]
   241          # For now, admin certs and CA certs are the same per @ASO
   242          adminCerts = certPemsList
   243          cacerts = adminCerts
   244          # Currently only 1 component, CN=<orgName>
   245          # name = self.getSelfSignedCert().get_subject().getComponents()[0][1]
   246          name = self.name
   247          fabricMSPConfig = msp_config_pb2.FabricMSPConfig(admins=adminCerts, root_certs=cacerts, name=name)
   248          mspConfig = msp_config_pb2.MSPConfig(config=fabricMSPConfig.SerializeToString(), type=0)
   249          return mspConfig
   250  
   251      def isInNetwork(self, network):
   252          for n in self.networks:
   253              if str(n)==str(network):
   254                  return True
   255          return False
   256  
   257      def getMspPrincipalAsRole(self, mspRoleTypeAsString):
   258          mspRole = msp_principal_pb2.MSPRole(msp_identifier=self.name, role=msp_principal_pb2.MSPRole.MSPRoleType.Value(mspRoleTypeAsString))
   259          mspPrincipal = msp_principal_pb2.MSPPrincipal(
   260              principal_classification=msp_principal_pb2.MSPPrincipal.Classification.Value('ROLE'),
   261              principal=mspRole.SerializeToString())
   262          return mspPrincipal
   263  
   264      def createCertificate(self, certReq):
   265          numYrs = 1
   266          return createCertificate(certReq, (self.signedCert, self.pKey), 1000, (0, 60 * 60 * 24 * 365 * numYrs))
   267  
   268      def addToNetwork(self, network):
   269          'Used to track which network this organization is defined in.'
   270          # assert network in Network, 'Network not recognized ({0}), expected to be one of ({1})'.format(network, list(Network))
   271          if not network in self.networks:
   272              self.networks.append(network)
   273  
   274  
   275  class Directory:
   276      def __init__(self):
   277          self.organizations = {}
   278          self.users = {}
   279          self.ordererAdminTuples = {}
   280  
   281      def getNamedCtxTuples(self):
   282          return self.ordererAdminTuples
   283  
   284      def _registerOrg(self, orgName):
   285          assert orgName not in self.organizations, "Organization already registered {0}".format(orgName)
   286          self.organizations[orgName] = Organization(orgName)
   287          return self.organizations[orgName]
   288  
   289      def _registerUser(self, userName):
   290          assert userName not in self.users, "User already registered {0}".format(userName)
   291          self.users[userName] = User(userName, directory=self)
   292          return self.users[userName]
   293  
   294      def getUser(self, userName, shouldCreate=False):
   295          if not userName in self.users and shouldCreate:
   296              # self.users[userName] = User(userName)
   297              self._registerUser(userName)
   298          return self.users[userName]
   299  
   300      def getUsers(self):
   301          return self.users
   302  
   303      def cleanup(self):
   304          '''Perform cleanup of resources'''
   305          [user.cleanup() for user in self.users.values()]
   306  
   307      def getOrganization(self, orgName, shouldCreate=False):
   308          if not orgName in self.organizations and shouldCreate:
   309              # self.organizations[orgName] = Organization(orgName)
   310              self._registerOrg(orgName)
   311          return self.organizations[orgName]
   312  
   313      def getOrganizations(self):
   314          return self.organizations
   315  
   316      def findCertByTuple(self, userName, contextName, orgName):
   317          ordererAdminTuple = NodeAdminTuple(user=userName, nodeName=contextName, organization=orgName)
   318          return self.ordererAdminTuples[ordererAdminTuple]
   319  
   320      def findCertForNodeAdminTuple(self, nodeAdminTuple):
   321          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   322          return self.ordererAdminTuples[nodeAdminTuple]
   323  
   324      def getCertAsPEM(self, nodeAdminTuple):
   325          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   326          return crypto.dump_certificate(crypto.FILETYPE_PEM, self.ordererAdminTuples[nodeAdminTuple])
   327  
   328      def findNodeAdminTuple(self, userName, contextName, orgName):
   329          nodeAdminTuple = NodeAdminTuple(user=userName, nodeName=contextName, organization=orgName)
   330          assert nodeAdminTuple in self.ordererAdminTuples, "Node admin tuple not found for: {0}".format(nodeAdminTuple)
   331          return nodeAdminTuple
   332  
   333      def getTrustedRootsForPeerNetworkAsPEM(self):
   334          pems = [peerOrg.getCertAsPEM() for peerOrg in [org for org in self.getOrganizations().values() if org.isInNetwork(Network.Peer)]]
   335          return "".join(pems)
   336  
   337      def getTrustedRootsForOrdererNetworkAsPEM(self):
   338          pems = [ordererOrg.getCertAsPEM() for ordererOrg in [org for org in self.getOrganizations().values() if org.isInNetwork(Network.Orderer)]]
   339          return "".join(pems)
   340  
   341  
   342      def registerOrdererAdminTuple(self, userName, ordererName, organizationName):
   343          ' Assign the user as orderer admin'
   344          ordererAdminTuple = NodeAdminTuple(user=userName, nodeName=ordererName, organization=organizationName)
   345          assert ordererAdminTuple not in self.ordererAdminTuples, "Orderer admin tuple already registered {0}".format(
   346              ordererAdminTuple)
   347          assert organizationName in self.organizations, "Orderer Organization not defined {0}".format(organizationName)
   348  
   349          user = self.getUser(userName, shouldCreate=True)
   350          certReq = user.createCertRequest(ordererAdminTuple.nodeName)
   351          userCert = self.getOrganization(organizationName).createCertificate(certReq)
   352  
   353          # Verify the newly created certificate
   354          store = crypto.X509Store()
   355          # Assuming a list of trusted certs
   356          for trustedCert in [self.getOrganization(organizationName).signedCert]:
   357              store.add_cert(trustedCert)
   358          # Create a certificate context using the store and the certificate to verify
   359          store_ctx = crypto.X509StoreContext(store, userCert)
   360          # Verify the certificate, returns None if it can validate the certificate
   361          store_ctx.verify_certificate()
   362          self.ordererAdminTuples[ordererAdminTuple] = userCert
   363          return ordererAdminTuple
   364  
   365  
   366  class AuthDSLHelper:
   367      @classmethod
   368      def Envelope(cls, signaturePolicy, identities):
   369          'Envelope builds an envelope message embedding a SignaturePolicy'
   370          return common_dot_policies_pb2.SignaturePolicyEnvelope(
   371              version=0,
   372              policy=signaturePolicy,
   373              identities=identities)
   374  
   375      @classmethod
   376      def NOutOf(cls, n, policies):
   377          'NOutOf creates a policy which requires N out of the slice of policies to evaluate to true'
   378          return common_dot_policies_pb2.SignaturePolicy(
   379              n_out_of=common_dot_policies_pb2.SignaturePolicy.NOutOf(
   380                  n=n,
   381                  policies=policies,
   382              ),
   383          )
   384  
   385      @classmethod
   386      def SignedBy(cls, index):
   387          'NOutOf creates a policy which requires N out of the slice of policies to evaluate to true'
   388          return common_dot_policies_pb2.SignaturePolicy(
   389              signed_by=index
   390          )
   391  
   392  class BootstrapHelper:
   393      KEY_CONSENSUS_TYPE = "ConsensusType"
   394      KEY_ORDERER_KAFKA_BROKERS = "KafkaBrokers"
   395      KEY_CHAIN_CREATION_POLICY_NAMES = "ChainCreationPolicyNames"
   396      KEY_CHANNEL_CREATION_POLICY = "ChannelCreationPolicy"
   397      KEY_CHANNEL_RESTRICTIONS = "ChannelRestrictions"
   398      KEY_CONSORTIUM = "Consortium"
   399      KEY_ACCEPT_ALL_POLICY = "AcceptAllPolicy"
   400      KEY_HASHING_ALGORITHM = "HashingAlgorithm"
   401      KEY_BLOCKDATA_HASHING_STRUCTURE = "BlockDataHashingStructure"
   402      KEY_BATCH_SIZE = "BatchSize"
   403      KEY_BATCH_TIMEOUT = "BatchTimeout"
   404      KEY_CREATIONPOLICY = "CreationPolicy"
   405      KEY_MSP_INFO = "MSP"
   406      KEY_ANCHOR_PEERS = "AnchorPeers"
   407  
   408      KEY_NEW_CONFIGURATION_ITEM_POLICY = "NewConfigurationItemPolicy"
   409      DEFAULT_CHAIN_CREATORS = [KEY_ACCEPT_ALL_POLICY]
   410  
   411      # ReadersPolicyKey is the key used for the read policy
   412      KEY_POLICY_READERS = "Readers"
   413      # WritersPolicyKey is the key used for the writer policy
   414      KEY_POLICY_WRITERS = "Writers"
   415      # AdminsPolicyKey is the key used for the admins policy
   416      KEY_POLICY_ADMINS = "Admins"
   417  
   418      KEY_POLICY_BLOCK_VALIDATION = "BlockValidation"
   419  
   420      # OrdererAddressesKey is the cb.ConfigItem type key name for the OrdererAddresses message
   421      KEY_ORDERER_ADDRESSES = "OrdererAddresses"
   422  
   423  
   424      DEFAULT_NONCE_SIZE = 24
   425  
   426      @classmethod
   427      def getNonce(cls):
   428          return rand.bytes(BootstrapHelper.DEFAULT_NONCE_SIZE)
   429  
   430      @classmethod
   431      def addSignatureToSignedConfigItem(cls, configUpdateEnvelope, (entity, mspId, cert)):
   432          serializedIdentity = identities_pb2.SerializedIdentity(mspid=mspId, id_bytes=crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   433          sigHeader = common_dot_common_pb2.SignatureHeader(creator=serializedIdentity.SerializeToString(),
   434                                                            nonce=BootstrapHelper.getNonce())
   435          sigHeaderBytes = sigHeader.SerializeToString()
   436          # Signature over the concatenation of configurationItem bytes and signatureHeader bytes
   437          signature = entity.sign(sigHeaderBytes + configUpdateEnvelope.config_update)
   438          # Now add new signature to Signatures repeated field
   439          newConfigSig = configUpdateEnvelope.signatures.add()
   440          newConfigSig.signature_header = sigHeaderBytes
   441          newConfigSig.signature = signature
   442  
   443      def __init__(self, chainId, lastModified=0, msgVersion=1, epoch=0, consensusType="solo", batchSize=10,
   444                   batchTimeout=".5s", absoluteMaxBytes=100000000, preferredMaxBytes=512 * 1024, signers=[]):
   445          self.chainId = str(chainId)
   446          self.lastModified = lastModified
   447          self.msgVersion = msgVersion
   448          self.epoch = epoch
   449          self.consensusType = consensusType
   450          self.batchSize = batchSize
   451          self.batchTimeout = batchTimeout
   452          self.absoluteMaxBytes = absoluteMaxBytes
   453          self.preferredMaxBytes = preferredMaxBytes
   454          self.signers = signers
   455  
   456      def makeChainHeader(self, type, txID="", extension='',
   457                          version=1,
   458                          timestamp=timestamp_pb2.Timestamp(seconds=int(time.time()), nanos=0)):
   459          return common_dot_common_pb2.ChannelHeader(type=type,
   460                                                   version=version,
   461                                                   timestamp=timestamp,
   462                                                   channel_id=self.chainId,
   463                                                   epoch=self.epoch,
   464                                                   tx_id=txID,
   465                                                   extension=extension)
   466  
   467      def makeSignatureHeader(self, serializeCertChain, nonce):
   468          return common_dot_common_pb2.SignatureHeader(creator=serializeCertChain,
   469                                                       nonce=nonce)
   470  
   471      def signConfigItem(self, configItem):
   472          # signedConfigItem = common_dot_configuration_pb2.SignedConfigurationItem(
   473          #     ConfigurationItem=configItem.SerializeToString(), Signatures=None)
   474          # return signedConfigItem
   475          return configItem
   476  
   477      def getConfigItem(self, commonConfigType, key, value):
   478          configItem = common_dot_configtx_pb2.ConfigItem(
   479              version=self.lastModified,
   480              configPath=commonConfigType,
   481              key=key,
   482              mod_policy=BootstrapHelper.KEY_NEW_CONFIGURATION_ITEM_POLICY,
   483              value=value)
   484          return configItem
   485  
   486      def computeBlockDataHash(self, blockData):
   487          return computeCryptoHash(blockData.SerializeToString())
   488  
   489  def getDirectory(context):
   490      if 'bootstrapDirectory' not in context:
   491          context.bootstrapDirectory = Directory()
   492      return context.bootstrapDirectory
   493  
   494  
   495  def getOrdererBootstrapAdmin(context, shouldCreate=False):
   496      directory = getDirectory(context)
   497      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=shouldCreate)
   498      return ordererBootstrapAdmin
   499  
   500  
   501  def addOrdererBootstrapAdminOrgReferences(context, policyName, orgNames):
   502      'Adds a key/value pair of policyName/[orgName,...]'
   503      directory = getDirectory(context)
   504      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=False)
   505      if not 'OrgReferences' in ordererBootstrapAdmin.tags:
   506          ordererBootstrapAdmin.tags['OrgReferences'] = {}
   507      policyNameToOrgNamesDict = ordererBootstrapAdmin.tags['OrgReferences']
   508      assert not policyName in policyNameToOrgNamesDict, "PolicyName '{0}' already registered with ordererBootstrapAdmin".format(
   509          policyName)
   510      policyNameToOrgNamesDict[policyName] = orgNames
   511      return policyNameToOrgNamesDict
   512  
   513  
   514  def getOrdererBootstrapAdminOrgReferences(context):
   515      directory = getDirectory(context)
   516      ordererBootstrapAdmin = directory.getUser(userName="ordererBootstrapAdmin", shouldCreate=False)
   517      if not 'OrgReferences' in ordererBootstrapAdmin.tags:
   518          ordererBootstrapAdmin.tags['OrgReferences'] = {}
   519      return ordererBootstrapAdmin.tags['OrgReferences']
   520  
   521  
   522  def getSignedMSPConfigItems(context, orgNames, channel_version=0, application_group_version=0, application_group_policy_version=0):
   523      directory = getDirectory(context)
   524      orgs = [directory.getOrganization(orgName) for orgName in orgNames]
   525  
   526      channel = common_dot_configtx_pb2.ConfigGroup()
   527      channel.version=channel_version
   528      channel.groups[ApplicationGroup].version=application_group_version
   529      for org in orgs:
   530          channel.groups[ApplicationGroup].groups[org.name].version = application_group_version
   531          channel.groups[ApplicationGroup].groups[org.name]
   532  
   533      # For now, setting same policies for each 'Non-Org' group
   534      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
   535      Policy = common_dot_policies_pb2.Policy
   536      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
   537      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
   538      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
   539      for group in [channel.groups[ApplicationGroup]]:
   540          group.policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP(
   541              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_READERS).SerializeToString()))
   542          group.policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP(
   543              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
   544          group.policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP(
   545              rule=ruleMajority, sub_policy=BootstrapHelper.KEY_POLICY_ADMINS).SerializeToString()))
   546      for group in [channel.groups[ApplicationGroup]]:
   547          group.policies[BootstrapHelper.KEY_POLICY_READERS].version=application_group_policy_version
   548          group.policies[BootstrapHelper.KEY_POLICY_WRITERS].version=application_group_policy_version
   549          group.policies[BootstrapHelper.KEY_POLICY_ADMINS].version=application_group_policy_version
   550  
   551      return [channel]
   552  
   553  
   554  def getAnchorPeersConfigGroup(context, nodeAdminTuples):
   555      directory = getDirectory(context)
   556      config_group = common_dot_configtx_pb2.ConfigGroup()
   557      for orgName, group in groupby([(nat.organization, nat) for nat in nodeAdminTuples], lambda x: x[0]):
   558          anchorPeers = peer_dot_configuration_pb2.AnchorPeers()
   559          for (k,nodeAdminTuple) in group:
   560              anchorPeer = anchorPeers.anchor_peers.add()
   561              anchorPeer.host = nodeAdminTuple.nodeName
   562              anchorPeer.port = 7051
   563              # anchorPeer.cert = crypto.dump_certificate(crypto.FILETYPE_PEM,
   564              #                                           directory.findCertForNodeAdminTuple(nodeAdminTuple))
   565          config_group.groups[ApplicationGroup].groups[orgName].values[BootstrapHelper.KEY_ANCHOR_PEERS].value=toValue(anchorPeers)
   566      return [config_group]
   567  
   568  def createSignedConfigItems(directory, consensus_type, consortium_name, version=1, channel_version=0, channel_consortium_version=0, configGroups=[]):
   569      channelConfig = common_dot_configtx_pb2.ConfigGroup()
   570      channelConfig.values[BootstrapHelper.KEY_CONSORTIUM].version=channel_consortium_version
   571      channelConfig.values[BootstrapHelper.KEY_CONSORTIUM].value=toValue(common_dot_configuration_pb2.Consortium(name=consortium_name))
   572      channelConfig.version = channel_version
   573      channelConfig.groups[ApplicationGroup].version = version
   574      for configGroup in configGroups:
   575          mergeConfigGroups(channelConfig, configGroup)
   576      return channelConfig
   577  
   578  
   579  def setDefaultPoliciesForOrgs(channel, orgs, group_name, version=0, policy_version=0):
   580      for org in orgs:
   581          groupName = group_name
   582          channel.groups[groupName].groups[org.name].version=version
   583          mspPrincipalForMemberRole = org.getMspPrincipalAsRole(mspRoleTypeAsString='MEMBER')
   584          signedBy = AuthDSLHelper.SignedBy(0)
   585  
   586          memberSignaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.NOutOf(1, [signedBy]), identities=[mspPrincipalForMemberRole])
   587          memberPolicy = common_dot_policies_pb2.Policy(
   588              type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"),
   589              policy=memberSignaturePolicyEnvelope.SerializeToString())
   590          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_READERS].version=policy_version
   591          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(memberPolicy)
   592          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_WRITERS].version=policy_version
   593          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(memberPolicy)
   594  
   595          mspPrincipalForAdminRole = org.getMspPrincipalAsRole(mspRoleTypeAsString='ADMIN')
   596          adminSignaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.NOutOf(1, [signedBy]), identities=[mspPrincipalForAdminRole])
   597          adminPolicy = common_dot_policies_pb2.Policy(
   598              type=common_dot_policies_pb2.Policy.PolicyType.Value("SIGNATURE"),
   599              policy=adminSignaturePolicyEnvelope.SerializeToString())
   600          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_ADMINS].version=policy_version
   601          channel.groups[groupName].groups[org.name].policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(adminPolicy)
   602  
   603          for pKey, pVal in channel.groups[groupName].groups[org.name].policies.iteritems():
   604              pVal.mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   605  
   606          # signaturePolicyEnvelope = AuthDSLHelper.Envelope(signaturePolicy=AuthDSLHelper.SignedBy(0), identities=[mspPrincipal])
   607  
   608  
   609  
   610  def createChannelConfigGroup(directory, hashingAlgoName="SHA256", consensusType="solo", batchTimeout="1s", batchSizeMaxMessageCount=10, batchSizeAbsoluteMaxBytes=100000000, batchSizePreferredMaxBytes=512 * 1024, channel_max_count=0):
   611  
   612      channel = common_dot_configtx_pb2.ConfigGroup()
   613      # channel.groups[ApplicationGroup] = common_dot_configtx_pb2.ConfigGroup()
   614      # channel.groups[OrdererGroup] = common_dot_configtx_pb2.ConfigGroup()
   615      # channel.groups[ApplicationGroup]
   616      channel.groups[OrdererGroup]
   617      # v = common_dot_configtx_pb2.ConfigItem.ConfigType.Value
   618      # configItems.append(bootstrapHelper.encodeHashingAlgorithm())
   619      channel.values[BootstrapHelper.KEY_HASHING_ALGORITHM].value = toValue(
   620          common_dot_configuration_pb2.HashingAlgorithm(name=hashingAlgoName))
   621  
   622      golangMathMaxUint32 = 4294967295
   623      channel.values[BootstrapHelper.KEY_BLOCKDATA_HASHING_STRUCTURE].value = toValue(
   624          common_dot_configuration_pb2.BlockDataHashingStructure(width=golangMathMaxUint32))
   625  
   626      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_SIZE].value = toValue(orderer_dot_configuration_pb2.BatchSize(maxMessageCount=batchSizeMaxMessageCount,absoluteMaxBytes=batchSizeAbsoluteMaxBytes,preferredMaxBytes=batchSizePreferredMaxBytes))
   627      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_BATCH_TIMEOUT].value = toValue(orderer_dot_configuration_pb2.BatchTimeout(timeout=batchTimeout))
   628      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_CONSENSUS_TYPE].value = toValue(orderer_dot_configuration_pb2.ConsensusType(type=consensusType))
   629      channel.groups[OrdererGroup].values[BootstrapHelper.KEY_CHANNEL_RESTRICTIONS].value = toValue(orderer_dot_configuration_pb2.ChannelRestrictions(max_count=channel_max_count))
   630  
   631  
   632      acceptAllPolicy = common_dot_policies_pb2.Policy(type=1, policy=AuthDSLHelper.Envelope(
   633          signaturePolicy=AuthDSLHelper.NOutOf(0, []), identities=[]).SerializeToString())
   634      # channel.policies[BootstrapHelper.KEY_ACCEPT_ALL_POLICY].policy.CopyFrom(acceptAllPolicy)
   635  
   636      # For now, setting same policies for each 'Non-Org' group
   637      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
   638      Policy = common_dot_policies_pb2.Policy
   639      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
   640      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
   641      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
   642      for group in [channel, channel.groups[OrdererGroup]]:
   643          group.policies[BootstrapHelper.KEY_POLICY_READERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP(
   644              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_READERS).SerializeToString()))
   645          group.policies[BootstrapHelper.KEY_POLICY_WRITERS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP(
   646              rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
   647          group.policies[BootstrapHelper.KEY_POLICY_ADMINS].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP(
   648              rule=ruleMajority, sub_policy=BootstrapHelper.KEY_POLICY_ADMINS).SerializeToString()))
   649          for pKey, pVal in group.policies.iteritems():
   650              pVal.mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   651  
   652      # Setting block validation policy for the orderer group
   653      channel.groups[OrdererGroup].policies[BootstrapHelper.KEY_POLICY_BLOCK_VALIDATION].policy.CopyFrom(Policy(type=typeImplicitMeta, policy=IMP(
   654          rule=ruleAny, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
   655      channel.groups[OrdererGroup].policies[BootstrapHelper.KEY_POLICY_BLOCK_VALIDATION].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
   656  
   657      # Add the orderer org groups MSPConfig info
   658      for ordererOrg in [org for org in directory.getOrganizations().values() if Network.Orderer in org.networks]:
   659          channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
   660              ordererOrg.getMSPConfig())
   661          channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
   662      # #Kafka specific
   663      # matchingNATs = [nat for nat in directory.getNamedCtxTuples() if (("orderer" in nat.user) and ("Signer" in nat.user) and ((compose_service in nat.nodeName)))]
   664      # for broker in [org for org in directory.getOrganizations().values() if Network.Orderer in org.networks]:
   665      #     channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
   666      #         ordererOrg.getMSPConfig())
   667      # channel.groups[OrdererGroup].values[BootstrapHelper.KEY_ORDERER_KAFKA_BROKERS].value = toValue(orderer_dot_configuration_pb2.KafkaBrokers(brokers=["kafka0:9092"]))
   668  
   669      for vKey, vVal in channel.groups[OrdererGroup].values.iteritems():
   670          vVal.mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
   671  
   672  
   673  
   674      # Now set policies for each org group (Both peer and orderer)
   675      #TODO: Revisit after Jason does a bit more refactoring on chain creation policy enforcement
   676      ordererOrgs = [o for o in directory.getOrganizations().values() if Network.Orderer in o.networks]
   677      setDefaultPoliciesForOrgs(channel, ordererOrgs , OrdererGroup, version=0, policy_version=0)
   678  
   679      #New OrdererAddress
   680      ordererAddress = common_dot_configuration_pb2.OrdererAddresses()
   681      for ordererNodeTuple, cert in [(user_node_tuple, cert) for user_node_tuple, cert in directory.ordererAdminTuples.iteritems() if
   682                        "orderer" in user_node_tuple.user and "signer" in user_node_tuple.user.lower()]:
   683          ordererAddress.addresses.append("{0}:7050".format(ordererNodeTuple.nodeName))
   684      assert len(ordererAddress.addresses) > 0, "No orderer nodes were found while trying to create channel ConfigGroup"
   685      channel.values[BootstrapHelper.KEY_ORDERER_ADDRESSES].value = toValue(ordererAddress)
   686  
   687  
   688      for pKey, pVal in channel.values.iteritems():
   689          pVal.mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
   690  
   691  
   692      return channel
   693  
   694  def createEnvelopeForMsg(directory, nodeAdminTuple, chainId, msg, typeAsString):
   695      # configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(last_update=envelope.SerializeToString())
   696      bootstrapHelper = BootstrapHelper(chainId=chainId)
   697      payloadChainHeader = bootstrapHelper.makeChainHeader(
   698          type=common_dot_common_pb2.HeaderType.Value(typeAsString))
   699  
   700      # Now the SignatureHeader
   701      org = directory.getOrganization(nodeAdminTuple.organization)
   702      user = directory.getUser(nodeAdminTuple.user)
   703      cert = directory.findCertForNodeAdminTuple(nodeAdminTuple)
   704      serializedIdentity = identities_pb2.SerializedIdentity(mspid=org.name, id_bytes=crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   705      serializedCreatorCertChain = serializedIdentity.SerializeToString()
   706      nonce = None
   707      payloadSignatureHeader = common_dot_common_pb2.SignatureHeader(
   708          creator=serializedCreatorCertChain,
   709          nonce=bootstrapHelper.getNonce(),
   710      )
   711  
   712      payloadHeader = common_dot_common_pb2.Header(
   713          channel_header=payloadChainHeader.SerializeToString(),
   714          signature_header=payloadSignatureHeader.SerializeToString(),
   715      )
   716      payload = common_dot_common_pb2.Payload(header=payloadHeader, data=msg.SerializeToString())
   717      payloadBytes = payload.SerializeToString()
   718      envelope = common_dot_common_pb2.Envelope(payload=payloadBytes, signature=user.sign(payloadBytes))
   719      return envelope
   720  
   721      return configEnvelope
   722  
   723  
   724  def createNewConfigUpdateEnvelope(channelConfig, chainId, readset_version=0):
   725      read_set = common_dot_configtx_pb2.ConfigGroup()
   726      read_set.values[BootstrapHelper.KEY_CONSORTIUM].version=readset_version
   727      read_set.values[BootstrapHelper.KEY_CONSORTIUM].value=channelConfig.values[BootstrapHelper.KEY_CONSORTIUM].value
   728      read_set.groups[ApplicationGroup].version=readset_version
   729      for key, _ in channelConfig.groups['Application'].groups.iteritems():
   730          read_set.groups[ApplicationGroup].groups[key]
   731      configUpdate = common_dot_configtx_pb2.ConfigUpdate(channel_id=chainId,
   732                                                          read_set=read_set,
   733                                                          write_set=channelConfig)
   734      configUpdateEnvelope = common_dot_configtx_pb2.ConfigUpdateEnvelope(config_update=configUpdate.SerializeToString(), signatures =[])
   735      return configUpdateEnvelope
   736  
   737  
   738  def mergeConfigGroups(configGroupTarget, configGroupSource):
   739      for k, v in configGroupSource.groups.iteritems():
   740          if k in configGroupTarget.groups.keys():
   741              mergeConfigGroups(configGroupTarget.groups[k], configGroupSource.groups[k])
   742          else:
   743              configGroupTarget.groups[k].MergeFrom(v)
   744      for k, v in configGroupSource.policies.iteritems():
   745          if k in configGroupTarget.policies.keys():
   746              mergeConfigGroups(configGroupTarget.policies[k], configGroupSource.policies[k])
   747          else:
   748              configGroupTarget.policies[k].MergeFrom(v)
   749      for k, v in configGroupSource.values.iteritems():
   750          assert not k in configGroupTarget.values.keys(), "Value already exists in target config group: {0}".format(k)
   751          configGroupTarget.values[k].CopyFrom(v)
   752  
   753  
   754  def createGenesisBlock(context, chainId, consensusType, nodeAdminTuple, signedConfigItems=[]):
   755      'Generates the genesis block for starting the oderers and for use in the chain config transaction by peers'
   756      # assert not "bootstrapGenesisBlock" in context,"Genesis block already created:\n{0}".format(context.bootstrapGenesisBlock)
   757      directory = getDirectory(context)
   758      assert len(directory.ordererAdminTuples) > 0, "No orderer admin tuples defined!!!"
   759  
   760      channelConfig = createChannelConfigGroup(directory=directory, consensusType=consensusType)
   761      for configGroup in signedConfigItems:
   762          mergeConfigGroups(channelConfig, configGroup)
   763  
   764      # (fileName, fileExist) = ContextHelper.GetHelper(context=context).getTmpPathForName(name="t",extension="protobuf")
   765      # with open(fileName, 'w') as f:
   766      #     f.write(channelConfig.SerializeToString())
   767  
   768      config = common_dot_configtx_pb2.Config(
   769          sequence=0,
   770          channel_group=channelConfig)
   771  
   772      configEnvelope = common_dot_configtx_pb2.ConfigEnvelope(config=config)
   773      envelope = createEnvelopeForMsg(directory=directory, chainId=chainId, nodeAdminTuple=nodeAdminTuple, msg=configEnvelope, typeAsString="CONFIG")
   774      blockData = common_dot_common_pb2.BlockData(data=[envelope.SerializeToString()])
   775  
   776      # Spoke with kostas, for orderer in general
   777      signaturesMetadata = ""
   778      lastConfigurationBlockMetadata = common_dot_common_pb2.Metadata(
   779          value=common_dot_common_pb2.LastConfig(index=0).SerializeToString()).SerializeToString()
   780      ordererConfigMetadata = ""
   781      transactionFilterMetadata = ""
   782      bootstrapHelper = BootstrapHelper(chainId="NOT_USED")
   783      block = common_dot_common_pb2.Block(
   784          header=common_dot_common_pb2.BlockHeader(
   785              number=0,
   786              previous_hash=None,
   787              data_hash=bootstrapHelper.computeBlockDataHash(blockData),
   788          ),
   789          data=blockData,
   790          metadata=common_dot_common_pb2.BlockMetadata(
   791              metadata=[signaturesMetadata, lastConfigurationBlockMetadata, transactionFilterMetadata,
   792                        ordererConfigMetadata]),
   793      )
   794  
   795      # Add this back once crypto certs are required
   796      for nodeAdminTuple in directory.ordererAdminTuples:
   797          userCert = directory.ordererAdminTuples[nodeAdminTuple]
   798          certAsPEM = crypto.dump_certificate(crypto.FILETYPE_PEM, userCert)
   799          # print("UserCert for orderer genesis:\n{0}\n".format(certAsPEM))
   800          # print("")
   801  
   802      return (block, envelope, channelConfig)
   803  
   804  
   805  class PathType(Enum):
   806      'Denotes whether Path relative to Local filesystem or Containers volume reference.'
   807      Local = 1
   808      Container = 2
   809  
   810  
   811  class CallbackHelper:
   812      def __init__(self, discriminator, volumeRootPathInContainer = "/var/hyperledger/bddtests"):
   813          self.volumeRootPathInContainer = volumeRootPathInContainer
   814          self.discriminator = discriminator
   815  
   816      def getVolumePath(self, composition, pathType=PathType.Local):
   817          assert pathType in PathType, "Expected pathType of {0}".format(PathType)
   818          basePath = "."
   819          if pathType == PathType.Container:
   820              basePath = self.volumeRootPathInContainer
   821          return "{0}/volumes/{1}/{2}".format(basePath, self.discriminator, composition.projectName)
   822  
   823      def getLocalMspConfigPath(self, composition, compose_service, pathType=PathType.Local):
   824          return "{0}/{1}/localMspConfig".format(self.getVolumePath(composition, pathType), compose_service)
   825  
   826      def getLocalTLSConfigPath(self, composition, compose_service, pathType=PathType.Local):
   827          return os.path.join(self.getVolumePath(composition, pathType), compose_service, "tls_config")
   828  
   829      def _getPathAndUserInfo(self, directory , composition, compose_service, nat_discriminator="Signer", pathType=PathType.Local):
   830          matchingNATs = [nat for nat in directory.getNamedCtxTuples() if ((compose_service in nat.user) and (nat_discriminator in nat.user) and ((compose_service in nat.nodeName)))]
   831          assert len(matchingNATs)==1, "Unexpected number of matching NodeAdminTuples: {0}".format(matchingNATs)
   832          localMspConfigPath = self.getLocalMspConfigPath(composition=composition, compose_service=compose_service,pathType=pathType)
   833          return (localMspConfigPath, matchingNATs[0])
   834  
   835      def getLocalMspConfigPrivateKeyPath(self, directory , composition, compose_service, pathType=PathType.Local):
   836          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, composition=composition, compose_service=compose_service, pathType=pathType)
   837          return "{0}/keystore/{1}.pem".format(localMspConfigPath, nodeAdminTuple.user)
   838  
   839      def getLocalMspConfigPublicCertPath(self, directory , composition, compose_service, pathType=PathType.Local):
   840          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, composition=composition, compose_service=compose_service, pathType=pathType)
   841          return "{0}/signcerts/{1}.pem".format(localMspConfigPath, nodeAdminTuple.user)
   842  
   843      def getTLSKeyPaths(self, pnt , composition, compose_service, pathType=PathType.Local):
   844          localTLSConfigPath = self.getLocalTLSConfigPath(composition, compose_service, pathType=pathType)
   845          certPath = os.path.join(localTLSConfigPath,
   846                                  "{0}-{1}-{2}-tls.crt".format(pnt.user, pnt.nodeName, pnt.organization))
   847          keyPath = os.path.join(localTLSConfigPath,
   848                                 "{0}-{1}-{2}-tls.key".format(pnt.user, pnt.nodeName, pnt.organization))
   849          return (keyPath, certPath)
   850  
   851  
   852      def getLocalMspConfigRootCertPath(self, directory , composition, compose_service, pathType=PathType.Local):
   853          (localMspConfigPath, nodeAdminTuple) = self._getPathAndUserInfo(directory=directory, composition=composition, compose_service=compose_service, pathType=pathType)
   854          return "{0}/cacerts/{1}.pem".format(localMspConfigPath, nodeAdminTuple.organization)
   855  
   856      def _createCryptoMaterial(self,directory , composition, compose_service, network):
   857          self._writeMspFiles(directory , composition, compose_service, network)
   858          self._writeTLSFiles(directory , composition, compose_service, network)
   859  
   860      def _writeMspFiles(self, directory , composition, compose_service, network):
   861          localMspConfigPath = self.getLocalMspConfigPath(composition, compose_service)
   862          os.makedirs("{0}/{1}".format(localMspConfigPath, "signcerts"))
   863          os.makedirs("{0}/{1}".format(localMspConfigPath, "admincerts"))
   864          os.makedirs("{0}/{1}".format(localMspConfigPath, "cacerts"))
   865          os.makedirs("{0}/{1}".format(localMspConfigPath, "keystore"))
   866          # Loop through directory and place Organization Certs into cacerts folder
   867          for targetOrg in [org for orgName, org in directory.organizations.items() if network in org.networks]:
   868              with open("{0}/cacerts/{1}.pem".format(localMspConfigPath, targetOrg.name), "w") as f:
   869                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, targetOrg.getSelfSignedCert()))
   870  
   871          # Loop through directory and place Organization Certs into admincerts folder
   872          # TODO: revisit this, ASO recommended for now
   873          for targetOrg in [org for orgName, org in directory.organizations.items() if network in org.networks]:
   874              with open("{0}/admincerts/{1}.pem".format(localMspConfigPath, targetOrg.name), "w") as f:
   875                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, targetOrg.getSelfSignedCert()))
   876  
   877          # Find the peer signer Tuple for this peer and add to signcerts folder
   878          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   879                            compose_service in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   880              # Put the PEM file in the signcerts folder
   881              with open("{0}/signcerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   882                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   883              # Put the associated private key into the keystore folder
   884              user = directory.getUser(pnt.user, shouldCreate=False)
   885              with open("{0}/keystore/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   886                  f.write(user.ecdsaSigningKey.to_pem())
   887  
   888          # Find the peer admin Tuple for this peer and add to admincerts folder
   889          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   890                            compose_service in peerNodeTuple.user and "admin" in peerNodeTuple.user.lower()]:
   891              # Put the PEM file in the signcerts folder
   892              with open("{0}/admincerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f:
   893                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
   894  
   895      def _writeTLSFiles(self, directory , composition, compose_service, network):
   896          localTLSConfigPath = self.getLocalTLSConfigPath(composition, compose_service)
   897          os.makedirs(localTLSConfigPath)
   898          # Find the peer signer Tuple for this peer and add to signcerts folder
   899          for pnt, cert in [(peerNodeTuple, cert) for peerNodeTuple, cert in directory.ordererAdminTuples.items() if
   900                            compose_service in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]:
   901              user = directory.getUser(userName=pnt.user)
   902              userTLSCert = directory.getOrganization(pnt.organization).createCertificate(user.createTLSCertRequest(pnt.nodeName))
   903              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, composition=composition, compose_service=compose_service, pathType=PathType.Local)
   904              with open(keyPath, 'w') as f:
   905                  f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, user.rsaSigningKey))
   906              with open(certPath, 'w') as f:
   907                  f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, userTLSCert))
   908  
   909      def _getMspId(self, compose_service, directory):
   910          matchingNATs = [nat for nat in directory.getNamedCtxTuples() if ((compose_service in nat.user) and ("Signer" in nat.user) and ((compose_service in nat.nodeName)))]
   911          assert len(matchingNATs)==1, "Unexpected number of matching NodeAdminTuples: {0}".format(matchingNATs)
   912          return matchingNATs[0].organization
   913  
   914  
   915  class OrdererGensisBlockCompositionCallback(compose.CompositionCallback, CallbackHelper):
   916      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
   917  
   918      def __init__(self, context, genesisBlock, genesisFileName="genesis_file"):
   919          CallbackHelper.__init__(self, discriminator="orderer")
   920          self.context = context
   921          self.genesisFileName = genesisFileName
   922          self.genesisBlock = genesisBlock
   923          compose.Composition.RegisterCallbackInContext(context, self)
   924  
   925      def getGenesisFilePath(self, composition, pathType=PathType.Local):
   926          return "{0}/{1}".format(self.getVolumePath(composition, pathType), self.genesisFileName)
   927  
   928      def getOrdererList(self, composition):
   929          return [serviceName for serviceName in composition.getServiceNames() if "orderer" in serviceName]
   930  
   931      def composing(self, composition, context):
   932          print("Will copy gensisiBlock over at this point ")
   933          os.makedirs(self.getVolumePath(composition))
   934          with open(self.getGenesisFilePath(composition), "wb") as f:
   935              f.write(self.genesisBlock.SerializeToString())
   936          directory = getDirectory(context)
   937  
   938          for ordererService in self.getOrdererList(composition):
   939              self._createCryptoMaterial(directory=directory,
   940                                         compose_service=ordererService,
   941                                         composition=composition,
   942                                         network=Network.Orderer)
   943  
   944      def decomposing(self, composition, context):
   945          'Will remove the orderer volume path folder for the context'
   946          shutil.rmtree(self.getVolumePath(composition))
   947  
   948      def getEnv(self, composition, context, env):
   949          directory = getDirectory(context)
   950          env["ORDERER_GENERAL_GENESISMETHOD"] = "file"
   951          env["ORDERER_GENERAL_GENESISFILE"] = self.getGenesisFilePath(composition, pathType=PathType.Container)
   952          for ordererService in self.getOrdererList(composition):
   953              localMspConfigPath = self.getLocalMspConfigPath(composition, ordererService, pathType=PathType.Container)
   954              env["{0}_ORDERER_GENERAL_LOCALMSPDIR".format(ordererService.upper())] = localMspConfigPath
   955              env["{0}_ORDERER_GENERAL_LOCALMSPID".format(ordererService.upper())] = self._getMspId(compose_service=ordererService, directory=directory)
   956              # TLS Settings
   957              (_, pnt) = self._getPathAndUserInfo(directory=directory, composition=composition, compose_service=ordererService, pathType=PathType.Container)
   958              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, composition=composition, compose_service=ordererService, pathType=PathType.Container)
   959              env["{0}_ORDERER_GENERAL_TLS_CERTIFICATE".format(ordererService.upper())] = certPath
   960              env["{0}_ORDERER_GENERAL_TLS_PRIVATEKEY".format(ordererService.upper())] = keyPath
   961              # env["{0}_ORDERER_GENERAL_TLS_ROOTCAS".format(ordererService.upper())] = "[{0}]".format(self.getLocalMspConfigRootCertPath(
   962              #     directory=directory, composition=composition, compose_service=ordererService, pathType=PathType.Container))
   963  
   964  class PeerCompositionCallback(compose.CompositionCallback, CallbackHelper):
   965      'Responsible for setting up Peer nodes upon composition'
   966  
   967      def __init__(self, context):
   968          CallbackHelper.__init__(self, discriminator="peer")
   969          self.context = context
   970          compose.Composition.RegisterCallbackInContext(context, self)
   971  
   972      def getPeerList(self, composition):
   973          return [serviceName for serviceName in composition.getServiceNames() if "peer" in serviceName]
   974  
   975      def composing(self, composition, context):
   976          'Will copy local MSP info over at this point for each peer node'
   977  
   978          directory = getDirectory(context)
   979  
   980          for peerService in self.getPeerList(composition):
   981              self._createCryptoMaterial(directory=directory,
   982                                         compose_service=peerService,
   983                                         composition=composition,
   984                                         network=Network.Peer)
   985  
   986      def decomposing(self, composition, context):
   987          'Will remove the orderer volume path folder for the context'
   988          shutil.rmtree(self.getVolumePath(composition))
   989  
   990      def getEnv(self, composition, context, env):
   991          directory = getDirectory(context)
   992          # First figure out which organization provided the signer cert for this
   993          for peerService in self.getPeerList(composition):
   994              localMspConfigPath = self.getLocalMspConfigPath(composition, peerService, pathType=PathType.Container)
   995              env["{0}_CORE_PEER_MSPCONFIGPATH".format(peerService.upper())] = localMspConfigPath
   996              env["{0}_CORE_PEER_LOCALMSPID".format(peerService.upper())] = self._getMspId(compose_service=peerService, directory=directory)
   997              # TLS Settings
   998              # env["{0}_CORE_PEER_TLS_ENABLED".format(peerService.upper())] = self._getMspId(compose_service=peerService, directory=directory)
   999              (_, pnt) = self._getPathAndUserInfo(directory=directory, composition=composition, compose_service=peerService, pathType=PathType.Container)
  1000              (keyPath, certPath) = self.getTLSKeyPaths(pnt=pnt, composition=composition, compose_service=peerService, pathType=PathType.Container)
  1001              env["{0}_CORE_PEER_TLS_CERT_FILE".format(peerService.upper())] = certPath
  1002              env["{0}_CORE_PEER_TLS_KEY_FILE".format(peerService.upper())] = keyPath
  1003              env["{0}_CORE_PEER_TLS_ROOTCERT_FILE".format(peerService.upper())] = self.getLocalMspConfigRootCertPath(
  1004                  directory=directory, composition=composition, compose_service=peerService, pathType=PathType.Container)
  1005              env["{0}_CORE_PEER_TLS_SERVERHOSTOVERRIDE".format(peerService.upper())] = peerService
  1006  
  1007  
  1008  def createConsortium(context, consortium_name, org_names):
  1009      channel = common_dot_configtx_pb2.ConfigGroup()
  1010      directory = getDirectory(context=context)
  1011      # Add the orderer org groups MSPConfig info to consortiums group
  1012      for consortium_org in [org for org in directory.getOrganizations().values() if org.name in org_names]:
  1013          # channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
  1014          channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
  1015              consortium_org.getMSPConfig())
  1016          channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1017      typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
  1018      Policy = common_dot_policies_pb2.Policy
  1019      IMP = common_dot_policies_pb2.ImplicitMetaPolicy
  1020      ruleAny = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ANY")
  1021      ruleAll = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("ALL")
  1022      ruleMajority = common_dot_policies_pb2.ImplicitMetaPolicy.Rule.Value("MAJORITY")
  1023      channel.groups[ConsortiumsGroup].groups[consortium_name].values[BootstrapHelper.KEY_CHANNEL_CREATION_POLICY].value = toValue(
  1024          Policy(type=typeImplicitMeta, policy=IMP(
  1025              rule=ruleAll, sub_policy=BootstrapHelper.KEY_POLICY_WRITERS).SerializeToString()))
  1026      channel.groups[ConsortiumsGroup].groups[consortium_name].values[BootstrapHelper.KEY_CHANNEL_CREATION_POLICY].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
  1027      # For now, setting same policies for each 'Non-Org' group
  1028      orgs = [directory.getOrganization(orgName) for orgName in org_names]
  1029      setDefaultPoliciesForOrgs(channel.groups[ConsortiumsGroup], orgs, consortium_name, version=0, policy_version=0)
  1030      return channel
  1031  
  1032  def setOrdererBootstrapGenesisBlock(genesisBlock):
  1033      'Responsible for setting the GensisBlock for the Orderer nodes upon composition'
  1034  
  1035  
  1036  def broadcastCreateChannelConfigTx(context, certAlias, composeService, chainId, configTxEnvelope, user):
  1037      dataFunc = lambda x: configTxEnvelope
  1038      user.broadcastMessages(context=context, numMsgsToBroadcast=1, composeService=composeService, chainID=chainId,
  1039                             dataFunc=dataFunc)
  1040  
  1041  
  1042  def getArgsFromContextForUser(context, userName):
  1043      directory = getDirectory(context)
  1044      # Update the chaincodeSpec ctorMsg for invoke
  1045      args = []
  1046      if 'table' in context:
  1047          if context.table:
  1048              # There are function arguments
  1049              user = directory.getUser(userName)
  1050              # Allow the user to specify expressions referencing tags in the args list
  1051              pattern = re.compile('\{(.*)\}$')
  1052              for arg in context.table[0].cells:
  1053                  m = pattern.match(arg)
  1054                  if m:
  1055                      # tagName reference found in args list
  1056                      tagName = m.groups()[0]
  1057                      # make sure the tagName is found in the users tags
  1058                      assert tagName in user.tags, "TagName '{0}' not found for user '{1}'".format(tagName,
  1059                                                                                                   user.getUserName())
  1060                      args.append(user.tags[tagName])
  1061                  else:
  1062                      # No tag referenced, pass the arg
  1063                      args.append(arg)
  1064      return args
  1065  
  1066  
  1067  def getChannelIdFromConfigUpdateEnvelope(config_update_envelope):
  1068      config_update = common_dot_configtx_pb2.ConfigUpdate()
  1069      config_update.ParseFromString(config_update_envelope.config_update)
  1070      return config_update