----------------------------------------------------------------------------------------------------------------------
The goal of this feature is to support attribute-based access control (ABAC) for both chaincode and fabric.
For fabric, see FAB-3752 for how this feature will be used by MSP to ensure that the caller has admin authority. For chaincode, the caller's attribute name and value will be accessible in order to make arbitrary authorization decisions based on user-defined attributes.

The fabric-ca-server already allows associating arbitrary user-defined attributes with an identity. This feature will support adding attributes to an ECert as an x509 extension in the clear or encrypted. When an attribute is encrypted in an ECert, a decryption key will be returned separately to the client (i.e. not part of the ECert). It is up to the client to decide how to pass the key to fabric or chaincode. For example, it may be passed in the transient data field of a transaction so that chaincode has access to it but it is not stored on the ledger. This should be the default behavior of an SDK.

So when an ECert is generated, the following decisions must be made:
1) Which (if any) attributes should be added to the certificate?
2) For each of these attributes,
2a) what if the identity does not have the attribute? Should we error or just skip the attribute?
2b) if the identity has an attribute, should it be encrypted or appear in the clear?

This behavior will be controlled as follows:

We add the following to an enrollment and reenrollment requests:

AttributeRequests []struct{
Name string,
Require bool, // error if the identity doesn't have the attribute
Encrypt bool, // encrypt the attribute in the ecert
}

If this is specified in the enrollment/reenrollment request, then use it to make attribute decisions.

The "fabric-ca-client register" CLI command will be enhanced to support the following:

# fabric-ca-client register -u ... -id.attrs <attrName>=<attrValue>[:ecert]
If the ":ecert" suffix is added to an attribute name and value when registered, then by default that
attribute will be added to the ECert when issued.
Examples:
# fabric-ca-client register --id.name user1 --id.secret user1pw --id.type user --id.affiliation org1 -id.attrs attr1=val1:ecert
Registers user1 with an attribute named "attr1" and value of "val1" and mark it as "ecert" so that it is included in
the user's ECert by default.
# FABRIC_CA_CLIENT_HOME=user1 fabric-ca-client enroll -u http://user1:user1pw@localhost:7054
Enroll user1. You can then print user1/msp/signcerts/cert.pem with openssl and see "attr1" with a value of "val1" in the certificate.

The above describes how to generate an ECert with attributes.
The following is the basic API for accessing the attributes in an ECert.

// Get attributes from a certificate with secretAttrInfo for encrypted attributes which is passed separately.
func GetAttributesFromCert(cert *x509.Certificate, secretAttrInfo string) (*Attributes, error)
// Get a list of attribute names
func (a *Attributes) Names() []string
// Determine if an attribute with a specified name is found
func (a *Attributes) Contains(attrName string) bool
// Get the value of an attribute
func (a *Attributes) Value(attrName string) (string, bool, error)