github.com/canhui/fabric_ca2_2@v2.0.0-alpha+incompatible/lib/attr/attribute.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package attr 8 9 import ( 10 "fmt" 11 "strconv" 12 "strings" 13 14 "github.com/cloudflare/cfssl/log" 15 "github.com/hyperledger/fabric-ca/api" 16 "github.com/hyperledger/fabric-ca/util" 17 "github.com/pkg/errors" 18 ) 19 20 // AttributeControl interface gets the attributes associated with an identity 21 type AttributeControl interface { 22 // GetAttribute returns the value for an attribute name 23 GetAttribute(name string) (*api.Attribute, error) 24 } 25 26 type attributeType int 27 28 const ( 29 // BOOLEAN indicates that the attribute is of type boolean 30 BOOLEAN attributeType = 1 + iota 31 // LIST indicates that the attribute is of type list 32 LIST 33 // FIXED indicates that the attribute value is fixed and can't be modified 34 FIXED 35 // CUSTOM indicates that the attribute is a custom attribute 36 CUSTOM 37 ) 38 39 // Attribute names 40 const ( 41 Roles = "hf.Registrar.Roles" 42 DelegateRoles = "hf.Registrar.DelegateRoles" 43 Revoker = "hf.Revoker" 44 IntermediateCA = "hf.IntermediateCA" 45 GenCRL = "hf.GenCRL" 46 RegistrarAttr = "hf.Registrar.Attributes" 47 AffiliationMgr = "hf.AffiliationMgr" 48 EnrollmentID = "hf.EnrollmentID" 49 Type = "hf.Type" 50 Affiliation = "hf.Affiliation" 51 ) 52 53 // CanRegisterRequestedAttributes validates that the registrar can register the requested attributes 54 func CanRegisterRequestedAttributes(reqAttrs []api.Attribute, user, registrar AttributeControl) error { 55 if len(reqAttrs) == 0 { 56 return nil 57 } 58 59 log.Debugf("Checking to see if registrar can register the requested attributes: %+v", reqAttrs) 60 61 for _, reqAttr := range reqAttrs { 62 // Check if registrar is allowed to register requested attributes 63 err := CanRegisterAttribute(&reqAttr, reqAttrs, user, registrar) 64 if err != nil { 65 return err 66 } 67 } 68 69 return nil 70 } 71 72 // CanRegisterAttribute will iterate through the values of registrar's 'hf.Registrar.Attributes' attribute to check if registrar can register the requested attributes 73 func CanRegisterAttribute(requestedAttr *api.Attribute, allRequestedAttrs []api.Attribute, user, registrar AttributeControl) error { 74 // Get registrar's 'hf.Registrar.Attributes' attribute to see which attributes registrar is allowed to register 75 registrarAttrs, err := registrar.GetAttribute(RegistrarAttr) 76 if err != nil { 77 return errors.Errorf("Failed to get attribute '%s': %s", RegistrarAttr, err) 78 } 79 if registrarAttrs.Value == "" { 80 return errors.Errorf("Registrar does not have any values for '%s' thus can't register any attributes", RegistrarAttr) 81 } 82 log.Debugf("Validating that registrar with the following values for hf.Registrar.Attributes '%+v' is authorized to register the requested attribute '%+v'", registrarAttrs.GetValue(), requestedAttr) 83 callerHfRegisterAttrSlice := util.GetSliceFromList(registrarAttrs.Value, ",") // Remove any whitespace between the values and split on comma 84 85 requestedAttrName := requestedAttr.GetName() 86 87 err = canRegisterAttr(requestedAttrName, callerHfRegisterAttrSlice) 88 if err != nil { 89 return err 90 } 91 92 attrControl, err := getAttributeControl(requestedAttrName) 93 if err != nil { 94 return err 95 } 96 97 err = attrControl.isRegistrarAuthorized(requestedAttr, allRequestedAttrs, user, registrar) 98 if err != nil { 99 return errors.Errorf("Registrar is not authorized to register attribute: %s", err) 100 } 101 102 return nil 103 } 104 105 // attributeMap contains the control definition for reserverd (hf.) attributes 106 var attributeMap = initAttrs() 107 108 func initAttrs() map[string]*attributeControl { 109 var attributeMap = make(map[string]*attributeControl) 110 111 booleanAttributes := []string{Revoker, IntermediateCA, GenCRL, AffiliationMgr} 112 113 for _, attr := range booleanAttributes { 114 attributeMap[attr] = &attributeControl{ 115 name: attr, 116 requiresOwnership: true, 117 attrType: BOOLEAN, 118 } 119 } 120 121 listAttributes := []string{Roles, DelegateRoles, RegistrarAttr} 122 123 for _, attr := range listAttributes { 124 attributeMap[attr] = &attributeControl{ 125 name: attr, 126 requiresOwnership: true, 127 attrType: LIST, 128 } 129 } 130 131 fixedValueAttributes := []string{EnrollmentID, Type, Affiliation} 132 133 for _, attr := range fixedValueAttributes { 134 attributeMap[attr] = &attributeControl{ 135 name: attr, 136 requiresOwnership: false, 137 attrType: FIXED, 138 } 139 } 140 141 return attributeMap 142 } 143 144 type attributeControl struct { 145 name string 146 requiresOwnership bool 147 attrType attributeType 148 } 149 150 func (ac *attributeControl) getName() string { 151 return ac.name 152 } 153 154 func (ac *attributeControl) isOwnershipRequired() bool { 155 return ac.requiresOwnership 156 } 157 158 func (ac *attributeControl) isRegistrarAuthorized(requestedAttr *api.Attribute, allRequestedAttrs []api.Attribute, user, registrar AttributeControl) error { 159 log.Debug("Performing authorization check...") 160 requestedAttrName := requestedAttr.GetName() 161 162 var callersAttrValue string 163 if ac.isOwnershipRequired() { 164 callersAttribute, err := registrar.GetAttribute(requestedAttrName) 165 if err != nil { 166 return errors.Errorf("Attribute '%s' requires ownership but the caller does not own this attribute: %s", requestedAttrName, err) 167 } 168 callersAttrValue = callersAttribute.GetValue() 169 170 log.Debugf("Checking if caller is authorized to register attribute '%s' with the requested value of '%s'", requestedAttrName, requestedAttr.GetValue()) 171 } 172 173 switch ac.attrType { 174 case BOOLEAN: 175 return ac.validateBooleanAttribute(requestedAttr, callersAttrValue) 176 case LIST: 177 return ac.validateListAttribute(requestedAttr, callersAttrValue, allRequestedAttrs, user) 178 case FIXED: 179 log.Debug("Requested attribute type is fixed") 180 return errors.Errorf("Cannot register fixed value attribute '%s'", ac.getName()) 181 case CUSTOM: 182 return nil 183 } 184 185 return nil 186 } 187 188 func (ac *attributeControl) validateBooleanAttribute(requestedAttr *api.Attribute, callersAttrValue string) error { 189 log.Debug("Requested attribute type is boolean") 190 requestedAttrValue := requestedAttr.GetValue() 191 192 callerAttrValueBool, err := strconv.ParseBool(callersAttrValue) 193 if err != nil { 194 return errors.Wrap(err, fmt.Sprintf("Failed to get boolean value of '%s'", callersAttrValue)) 195 } 196 if callerAttrValueBool { 197 // Deleting an attribute if empty string is requested as value for attribute, no further validation necessary 198 if requestedAttrValue == "" { 199 return nil 200 } 201 _, err := strconv.ParseBool(requestedAttrValue) 202 if err != nil { 203 return errors.Wrap(err, fmt.Sprintf("Failed to get boolean value of '%s'", requestedAttrValue)) 204 } 205 return nil 206 } 207 return errors.Errorf("Caller has a value of 'false' for boolean attribute '%s', can't perform any actions on this attribute", ac.getName()) 208 } 209 210 func (ac *attributeControl) validateListAttribute(requestedAttr *api.Attribute, callersAttrValue string, allRequestedAttrs []api.Attribute, user AttributeControl) error { 211 log.Debug("Requested attribute type is list") 212 requestedAttrValue := requestedAttr.GetValue() 213 214 // Deleting an attribute if empty string is requested as value for attribute, no further validation necessary 215 if requestedAttrValue == "" { 216 return nil 217 } 218 219 callerRegisterAttrSlice := util.GetSliceFromList(callersAttrValue, ",") // Remove any whitespace between the values and split on comma 220 221 // hf.Registrar.Attribute is a special type of list attribute. Need to check all the 222 // requested attribute names as values to this attribute to make sure caller is allowed to register 223 if ac.getName() == RegistrarAttr { 224 err := checkHfRegistrarAttrValues(requestedAttr, allRequestedAttrs, user, callerRegisterAttrSlice) 225 if err != nil { 226 return err 227 } 228 return nil 229 } 230 // Make sure the values requested for attribute is equal to or a subset of the registrar's attribute 231 err := ac.IsSubsetOf(requestedAttrValue, callersAttrValue) 232 if err != nil { 233 return err 234 } 235 // If requested attribute is 'hf.Registrar.DeletegateRoles', make sure it is equal or a subset of the user's hf.Registrar.Roles attribute 236 if ac.getName() == DelegateRoles { 237 err := checkDelegateRoleValues(allRequestedAttrs, user) 238 if err != nil { 239 return err 240 } 241 } 242 return nil 243 } 244 245 func (ac *attributeControl) IsSubsetOf(requestedAttrValue, callersAttrValue string) error { 246 if (ac.getName() == Roles || ac.getName() == DelegateRoles) && util.ListContains(callersAttrValue, "*") { 247 return nil 248 } 249 err := util.IsSubsetOf(requestedAttrValue, callersAttrValue) 250 if err != nil { 251 return errors.WithMessage(err, fmt.Sprintf("The requested values for attribute '%s' is a superset of the caller's attribute value", ac.getName())) 252 } 253 return nil 254 } 255 256 // Check if registrar has the proper authority to register the values for 'hf.Registrar.Attributes'. 257 // Registering 'hf.Registrar.Attributes' with a value that has a 'hf.' prefix requires that the user 258 // being registered to possess that hf. attribute. For example, if attribute is 'hf.Registrar.Attributes=hf.Revoker' 259 // then user being registered must possess 'hf.Revoker' for this to be a valid request. 260 func checkHfRegistrarAttrValues(reqAttr *api.Attribute, reqAttrs []api.Attribute, user AttributeControl, callerRegisterAttrSlice []string) error { 261 log.Debug("Perform ownshership check for requested 'hf.' attributes for the values of 'hf.Registrar.Attributes'") 262 263 valuesRequestedForHfRegistrarAttr := util.GetSliceFromList(reqAttr.Value, ",") // Remove any whitespace between the values and split on comma 264 for _, requestedAttrValue := range valuesRequestedForHfRegistrarAttr { 265 err := canRegisterAttr(requestedAttrValue, callerRegisterAttrSlice) 266 if err != nil { 267 return err 268 } 269 if strings.HasPrefix(requestedAttrValue, "hf.") { 270 log.Debugf("Checking if value '%s' for hf.Registrar.Attribute is owned by user", requestedAttrValue) 271 if !Exists(reqAttrs, requestedAttrValue) { 272 // Attribute not present in the list of attributes being requested along side 'hf.Registrar.Attributes' 273 // if user equals nil, this is a new user registration request 274 if user == nil { 275 return errors.Errorf("Requesting value of '%s' for 'hf.Registrar.Attributes', but the identity being registered is not being registered with this attribute", requestedAttrValue) 276 } 277 // If user not equal nil (modify user request), check to see if it possesses the attribute 278 _, err := user.GetAttribute(requestedAttrValue) 279 if err != nil { 280 return errors.Errorf("Requesting value of '%s' for 'hf.Registrar.Attributes', but the identity does not possess this attribute nor is it being registered with this attribute", requestedAttrValue) 281 } 282 } 283 } 284 } 285 return nil 286 } 287 288 func canRegisterAttr(requestedAttrName string, callerRegisterAttrSlice []string) error { 289 log.Debugf("Checking if registrar can register attribute: %s", requestedAttrName) 290 291 for _, regAttr := range callerRegisterAttrSlice { 292 if strings.HasSuffix(regAttr, "*") { // Wildcard matching 293 if strings.HasPrefix(requestedAttrName, strings.TrimRight(regAttr, "*")) { 294 return nil 295 } 296 } else { 297 if requestedAttrName == regAttr { // Exact name matching 298 return nil 299 } 300 } 301 } 302 303 return errors.Errorf("Attribute is not part of caller's '%s' attribute list", callerRegisterAttrSlice) 304 } 305 306 // Make sure delegateRoles is not larger than roles 307 func checkDelegateRoleValues(reqAttrs []api.Attribute, user AttributeControl) error { 308 roles := GetAttrValue(reqAttrs, Roles) 309 if roles == "" { // If roles is not being updated in this request, query to get the current value of roles of user 310 if user != nil { // If the is a user modify request, check to see if attribute already exists for user 311 currentRoles, err := user.GetAttribute(Roles) 312 if err == nil { 313 roles = currentRoles.GetValue() 314 } 315 } 316 } 317 if util.ListContains(roles, "*") { 318 return nil 319 } 320 delegateRoles := GetAttrValue(reqAttrs, DelegateRoles) 321 err := util.IsSubsetOf(delegateRoles, roles) 322 if err != nil { 323 return errors.New("The delegateRoles field is a superset of roles") 324 } 325 return nil 326 } 327 328 func getAttributeControl(attrName string) (*attributeControl, error) { 329 attrControl, found := attributeMap[attrName] 330 if found { 331 return attrControl, nil 332 } 333 334 if strings.HasPrefix(attrName, "hf.") { 335 return nil, errors.Errorf("Registering attribute '%s' using a reserved prefix 'hf.', however this not a supported reserved attribute", attrName) 336 } 337 338 return &attributeControl{ 339 name: attrName, 340 requiresOwnership: false, 341 attrType: CUSTOM, 342 }, nil 343 } 344 345 // Exists searches 'attrs' for the attribute with name 'name' and returns 346 // true if found 347 func Exists(attrs []api.Attribute, name string) bool { 348 for _, attr := range attrs { 349 if attr.Name == name { 350 return true 351 } 352 } 353 return false 354 } 355 356 // GetAttrValue searches 'attrs' for the attribute with name 'name' and returns 357 // its value, or "" if not found. 358 func GetAttrValue(attrs []api.Attribute, name string) string { 359 for _, attr := range attrs { 360 if attr.Name == name { 361 return attr.Value 362 } 363 } 364 return "" 365 } 366 367 // ConvertAttrs converts attribute string into an Attribute object array 368 func ConvertAttrs(inAttrs map[string]string) ([]api.Attribute, error) { 369 var outAttrs []api.Attribute 370 for name, value := range inAttrs { 371 sattr := strings.Split(value, ":") 372 if len(sattr) > 2 { 373 return []api.Attribute{}, errors.Errorf("Multiple ':' characters not allowed "+ 374 "in attribute specification '%s'; The attributes have been discarded!", value) 375 } 376 attrFlag := "" 377 if len(sattr) > 1 { 378 attrFlag = sattr[1] 379 } 380 ecert := false 381 switch strings.ToLower(attrFlag) { 382 case "": 383 case "ecert": 384 ecert = true 385 default: 386 return []api.Attribute{}, errors.Errorf("Invalid attribute flag: '%s'", attrFlag) 387 } 388 outAttrs = append(outAttrs, api.Attribute{ 389 Name: name, 390 Value: sattr[0], 391 ECert: ecert, 392 }) 393 } 394 return outAttrs, nil 395 }