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