github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/common/policies/policy.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package policies 18 19 import ( 20 "fmt" 21 "strings" 22 23 cb "github.com/hyperledger/fabric/protos/common" 24 25 logging "github.com/op/go-logging" 26 ) 27 28 const ( 29 // Path separator is used to separate policy names in paths 30 PathSeparator = "/" 31 32 // ChannelPrefix is used in the path of standard channel policy managers 33 ChannelPrefix = "Channel" 34 35 // ApplicationPrefix is used in the path of standard application policy paths 36 ApplicationPrefix = "Application" 37 38 // OrdererPrefix is used in the path of standard orderer policy paths 39 OrdererPrefix = "Orderer" 40 41 // ChannelApplicationReaders is the label for the channel's application readers policy 42 ChannelApplicationReaders = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Readers" 43 44 // ChannelApplicationWriters is the label for the channel's application writers policy 45 ChannelApplicationWriters = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Writers" 46 47 // ChannelApplicationAdmins is the label for the channel's application admin policy 48 ChannelApplicationAdmins = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Admins" 49 50 // BlockValidation is the label for the policy which should validate the block signatures for the channel 51 BlockValidation = PathSeparator + ChannelPrefix + PathSeparator + OrdererPrefix + PathSeparator + "BlockValidation" 52 ) 53 54 var logger = logging.MustGetLogger("common/policies") 55 56 // Policy is used to determine if a signature is valid 57 type Policy interface { 58 // Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy 59 Evaluate(signatureSet []*cb.SignedData) error 60 } 61 62 // Manager is a read only subset of the policy ManagerImpl 63 type Manager interface { 64 // GetPolicy returns a policy and true if it was the policy requested, or false if it is the default policy 65 GetPolicy(id string) (Policy, bool) 66 67 // Manager returns the sub-policy manager for a given path and whether it exists 68 Manager(path []string) (Manager, bool) 69 70 // Basepath returns the basePath the manager was instantiated with 71 BasePath() string 72 73 // Policies returns all policy names defined in the manager 74 PolicyNames() []string 75 } 76 77 // Proposer is the interface used by the configtx manager for policy management 78 type Proposer interface { 79 // BeginPolicyProposals starts a policy update transaction 80 BeginPolicyProposals(groups []string) ([]Proposer, error) 81 82 // ProposePolicy createss a pending policy update from a ConfigPolicy 83 ProposePolicy(name string, policy *cb.ConfigPolicy) error 84 85 // RollbackProposals discards the pending policy updates 86 RollbackProposals() 87 88 // CommitProposals commits the pending policy updates 89 CommitProposals() 90 91 // PreCommit tests if a commit will apply 92 PreCommit() error 93 } 94 95 // Provider provides the backing implementation of a policy 96 type Provider interface { 97 // NewPolicy creates a new policy based on the policy bytes 98 NewPolicy(data []byte) (Policy, error) 99 } 100 101 type policyConfig struct { 102 policies map[string]Policy 103 managers map[string]*ManagerImpl 104 imps []*implicitMetaPolicy 105 } 106 107 // ManagerImpl is an implementation of Manager and configtx.ConfigHandler 108 // In general, it should only be referenced as an Impl for the configtx.ConfigManager 109 type ManagerImpl struct { 110 parent *ManagerImpl 111 basePath string 112 fqPrefix string 113 providers map[int32]Provider 114 config *policyConfig 115 pendingConfig *policyConfig 116 } 117 118 // NewManagerImpl creates a new ManagerImpl with the given CryptoHelper 119 func NewManagerImpl(basePath string, providers map[int32]Provider) *ManagerImpl { 120 _, ok := providers[int32(cb.Policy_IMPLICIT_META)] 121 if ok { 122 logger.Panicf("ImplicitMetaPolicy type must be provider by the policy manager") 123 } 124 125 return &ManagerImpl{ 126 basePath: basePath, 127 fqPrefix: PathSeparator + basePath + PathSeparator, 128 providers: providers, 129 config: &policyConfig{ 130 policies: make(map[string]Policy), 131 managers: make(map[string]*ManagerImpl), 132 }, 133 } 134 } 135 136 type rejectPolicy string 137 138 func (rp rejectPolicy) Evaluate(signedData []*cb.SignedData) error { 139 return fmt.Errorf("No such policy type: %s", rp) 140 } 141 142 // Basepath returns the basePath the manager was instnatiated with 143 func (pm *ManagerImpl) BasePath() string { 144 return pm.basePath 145 } 146 147 func (pm *ManagerImpl) PolicyNames() []string { 148 policyNames := make([]string, len(pm.config.policies)) 149 i := 0 150 for policyName := range pm.config.policies { 151 policyNames[i] = policyName 152 i++ 153 } 154 return policyNames 155 } 156 157 // Manager returns the sub-policy manager for a given path and whether it exists 158 func (pm *ManagerImpl) Manager(path []string) (Manager, bool) { 159 if len(path) == 0 { 160 return pm, true 161 } 162 163 m, ok := pm.config.managers[path[0]] 164 if !ok { 165 return nil, false 166 } 167 168 return m.Manager(path[1:]) 169 } 170 171 // GetPolicy returns a policy and true if it was the policy requested, or false if it is the default reject policy 172 func (pm *ManagerImpl) GetPolicy(id string) (Policy, bool) { 173 if id == "" { 174 logger.Errorf("Returning dummy reject all policy because no policy ID supplied") 175 return rejectPolicy(id), false 176 } 177 var relpath string 178 179 if strings.HasPrefix(id, PathSeparator) { 180 if pm.parent != nil { 181 return pm.parent.GetPolicy(id) 182 } 183 if !strings.HasPrefix(id, pm.fqPrefix) { 184 if logger.IsEnabledFor(logging.DEBUG) { 185 logger.Debugf("Requested policy from root manager with wrong basePath: %s, returning rejectAll", id) 186 } 187 return rejectPolicy(id), false 188 } 189 relpath = id[len(pm.fqPrefix):] 190 } else { 191 relpath = id 192 } 193 194 policy, ok := pm.config.policies[relpath] 195 if !ok { 196 if logger.IsEnabledFor(logging.DEBUG) { 197 logger.Debugf("Returning dummy reject all policy because %s could not be found in /%s/%s", id, pm.basePath, relpath) 198 } 199 return rejectPolicy(relpath), false 200 } 201 if logger.IsEnabledFor(logging.DEBUG) { 202 logger.Debugf("Returning policy %s for evaluation", relpath) 203 } 204 return policy, true 205 } 206 207 // BeginPolicies is used to start a new config proposal 208 func (pm *ManagerImpl) BeginPolicyProposals(groups []string) ([]Proposer, error) { 209 if pm.pendingConfig != nil { 210 logger.Panicf("Programming error, cannot call begin in the middle of a proposal") 211 } 212 213 pm.pendingConfig = &policyConfig{ 214 policies: make(map[string]Policy), 215 managers: make(map[string]*ManagerImpl), 216 } 217 218 managers := make([]Proposer, len(groups)) 219 for i, group := range groups { 220 newManager := NewManagerImpl(group, pm.providers) 221 newManager.parent = pm 222 pm.pendingConfig.managers[group] = newManager 223 managers[i] = newManager 224 } 225 return managers, nil 226 } 227 228 // RollbackProposals is used to abandon a new config proposal 229 func (pm *ManagerImpl) RollbackProposals() { 230 pm.pendingConfig = nil 231 } 232 233 // PreCommit is currently a no-op for the policy manager and always returns nil 234 func (pm *ManagerImpl) PreCommit() error { 235 return nil 236 } 237 238 // CommitProposals is used to commit a new config proposal 239 func (pm *ManagerImpl) CommitProposals() { 240 if pm.pendingConfig == nil { 241 logger.Panicf("Programming error, cannot call commit without an existing proposal") 242 } 243 244 for managerPath, m := range pm.pendingConfig.managers { 245 for _, policyName := range m.PolicyNames() { 246 fqKey := managerPath + PathSeparator + policyName 247 pm.pendingConfig.policies[fqKey], _ = m.GetPolicy(policyName) 248 logger.Debugf("In commit adding relative sub-policy %s to %s", fqKey, pm.basePath) 249 } 250 } 251 252 // Now that all the policies are present, initialize the meta policies 253 for _, imp := range pm.pendingConfig.imps { 254 imp.initialize(pm.pendingConfig) 255 } 256 257 pm.config = pm.pendingConfig 258 pm.pendingConfig = nil 259 260 if pm.parent == nil && pm.basePath == ChannelPrefix { 261 if _, ok := pm.config.managers[ApplicationPrefix]; ok { 262 // Check for default application policies if the application component is defined 263 for _, policyName := range []string{ 264 ChannelApplicationReaders, 265 ChannelApplicationWriters, 266 ChannelApplicationAdmins} { 267 _, ok := pm.GetPolicy(policyName) 268 if !ok { 269 logger.Warningf("Current configuration has no policy '%s', this will likely cause problems in production systems", policyName) 270 } else { 271 logger.Debugf("As expected, current configuration has policy '%s'", policyName) 272 } 273 } 274 } 275 if _, ok := pm.config.managers[OrdererPrefix]; ok { 276 for _, policyName := range []string{BlockValidation} { 277 _, ok := pm.GetPolicy(policyName) 278 if !ok { 279 logger.Warningf("Current configuration has no policy '%s', this will likely cause problems in production systems", policyName) 280 } else { 281 logger.Debugf("As expected, current configuration has policy '%s'", policyName) 282 } 283 } 284 } 285 } 286 } 287 288 // ProposePolicy takes key, path, and ConfigPolicy and registers it in the proposed PolicyManager, or errors 289 func (pm *ManagerImpl) ProposePolicy(key string, configPolicy *cb.ConfigPolicy) error { 290 policy := configPolicy.Policy 291 if policy == nil { 292 return fmt.Errorf("Policy cannot be nil") 293 } 294 295 var cPolicy Policy 296 297 if policy.Type == int32(cb.Policy_IMPLICIT_META) { 298 imp, err := newImplicitMetaPolicy(policy.Policy) 299 if err != nil { 300 return err 301 } 302 pm.pendingConfig.imps = append(pm.pendingConfig.imps, imp) 303 cPolicy = imp 304 } else { 305 provider, ok := pm.providers[int32(policy.Type)] 306 if !ok { 307 return fmt.Errorf("Unknown policy type: %v", policy.Type) 308 } 309 310 var err error 311 cPolicy, err = provider.NewPolicy(policy.Policy) 312 if err != nil { 313 return err 314 } 315 } 316 317 pm.pendingConfig.policies[key] = cPolicy 318 319 logger.Debugf("Proposed new policy %s for %s", key, pm.basePath) 320 return nil 321 }