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  }