github.com/ldc1995/fabric-ca@v2.0.0-alpha.0.20200422214819-8d49c278c386+incompatible/lib/identity.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  	"net/http"
    13  	"strconv"
    14  
    15  	"github.com/cloudflare/cfssl/log"
    16  	"github.com/hyperledger/fabric-ca/api"
    17  	"github.com/hyperledger/fabric-ca/lib/client/credential"
    18  	"github.com/hyperledger/fabric-ca/lib/client/credential/idemix"
    19  	"github.com/hyperledger/fabric-ca/lib/client/credential/x509"
    20  	"github.com/hyperledger/fabric-ca/lib/common"
    21  	"github.com/hyperledger/fabric-ca/util"
    22  	"github.com/pkg/errors"
    23  )
    24  
    25  // Identity is fabric-ca's implementation of an identity
    26  type Identity struct {
    27  	name   string
    28  	client *Client
    29  	creds  []credential.Credential
    30  }
    31  
    32  // NewIdentity is the constructor for identity
    33  func NewIdentity(client *Client, name string, creds []credential.Credential) *Identity {
    34  	id := new(Identity)
    35  	id.name = name
    36  	id.client = client
    37  	id.creds = creds
    38  	return id
    39  }
    40  
    41  // GetName returns the identity name
    42  func (i *Identity) GetName() string {
    43  	return i.name
    44  }
    45  
    46  // GetClient returns the client associated with this identity
    47  func (i *Identity) GetClient() *Client {
    48  	return i.client
    49  }
    50  
    51  // GetIdemixCredential returns Idemix credential of this identity
    52  func (i *Identity) GetIdemixCredential() credential.Credential {
    53  	for _, cred := range i.creds {
    54  		if cred.Type() == idemix.CredType {
    55  			return cred
    56  		}
    57  	}
    58  	return nil
    59  }
    60  
    61  // GetX509Credential returns X509 credential of this identity
    62  func (i *Identity) GetX509Credential() credential.Credential {
    63  	for _, cred := range i.creds {
    64  		if cred.Type() == x509.CredType {
    65  			return cred
    66  		}
    67  	}
    68  	return nil
    69  }
    70  
    71  // GetECert returns the enrollment certificate signer for this identity
    72  // Returns nil if the identity does not have a X509 credential
    73  func (i *Identity) GetECert() *x509.Signer {
    74  	for _, cred := range i.creds {
    75  		if cred.Type() == x509.CredType {
    76  			v, _ := cred.Val()
    77  			if v != nil {
    78  				s, _ := v.(*x509.Signer)
    79  				return s
    80  			}
    81  		}
    82  	}
    83  	return nil
    84  }
    85  
    86  // Register registers a new identity
    87  // @param req The registration request
    88  func (i *Identity) Register(req *api.RegistrationRequest) (rr *api.RegistrationResponse, err error) {
    89  	log.Debugf("Register %+v", req)
    90  	if req.Name == "" {
    91  		return nil, errors.New("Register was called without a Name set")
    92  	}
    93  
    94  	reqBody, err := util.Marshal(req, "RegistrationRequest")
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  
    99  	// Send a post to the "register" endpoint with req as body
   100  	resp := &api.RegistrationResponse{}
   101  	err = i.Post("register", reqBody, resp, nil)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	log.Debug("The register request completed successfully")
   107  	return resp, nil
   108  }
   109  
   110  // RegisterAndEnroll registers and enrolls an identity and returns the identity
   111  func (i *Identity) RegisterAndEnroll(req *api.RegistrationRequest) (*Identity, error) {
   112  	if i.client == nil {
   113  		return nil, errors.New("No client is associated with this identity")
   114  	}
   115  	rresp, err := i.Register(req)
   116  	if err != nil {
   117  		return nil, errors.WithMessage(err, fmt.Sprintf("Failed to register %s", req.Name))
   118  	}
   119  	eresp, err := i.client.Enroll(&api.EnrollmentRequest{
   120  		Name:   req.Name,
   121  		Secret: rresp.Secret,
   122  	})
   123  	if err != nil {
   124  		return nil, errors.WithMessage(err, fmt.Sprintf("Failed to enroll %s", req.Name))
   125  	}
   126  	return eresp.Identity, nil
   127  }
   128  
   129  // Reenroll reenrolls an existing Identity and returns a new Identity
   130  // @param req The reenrollment request
   131  func (i *Identity) Reenroll(req *api.ReenrollmentRequest) (*EnrollmentResponse, error) {
   132  	log.Debugf("Reenrolling %s", util.StructToString(req))
   133  
   134  	csrPEM, key, err := i.client.GenCSR(req.CSR, i.GetName())
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	reqNet := &api.ReenrollmentRequestNet{
   140  		CAName:   req.CAName,
   141  		AttrReqs: req.AttrReqs,
   142  	}
   143  
   144  	// Get the body of the request
   145  	if req.CSR != nil {
   146  		reqNet.SignRequest.Hosts = req.CSR.Hosts
   147  	}
   148  	reqNet.SignRequest.Request = string(csrPEM)
   149  	reqNet.SignRequest.Profile = req.Profile
   150  	reqNet.SignRequest.Label = req.Label
   151  
   152  	body, err := util.Marshal(reqNet, "SignRequest")
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	var result common.EnrollmentResponseNet
   157  	err = i.Post("reenroll", body, &result, nil)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	return i.client.newEnrollmentResponse(&result, i.GetName(), key)
   162  }
   163  
   164  // Revoke the identity associated with 'id'
   165  func (i *Identity) Revoke(req *api.RevocationRequest) (*api.RevocationResponse, error) {
   166  	log.Debugf("Entering identity.Revoke %+v", req)
   167  	reqBody, err := util.Marshal(req, "RevocationRequest")
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	var result revocationResponseNet
   172  	err = i.Post("revoke", reqBody, &result, nil)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	log.Debugf("Successfully revoked certificates: %+v", req)
   177  	crl, err := util.B64Decode(result.CRL)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return &api.RevocationResponse{RevokedCerts: result.RevokedCerts, CRL: crl}, nil
   182  }
   183  
   184  // RevokeSelf revokes the current identity and all certificates
   185  func (i *Identity) RevokeSelf() (*api.RevocationResponse, error) {
   186  	name := i.GetName()
   187  	log.Debugf("RevokeSelf %s", name)
   188  	req := &api.RevocationRequest{
   189  		Name: name,
   190  	}
   191  	return i.Revoke(req)
   192  }
   193  
   194  // GenCRL generates CRL
   195  func (i *Identity) GenCRL(req *api.GenCRLRequest) (*api.GenCRLResponse, error) {
   196  	log.Debugf("Entering identity.GenCRL %+v", req)
   197  	reqBody, err := util.Marshal(req, "GenCRLRequest")
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	var result genCRLResponseNet
   202  	err = i.Post("gencrl", reqBody, &result, nil)
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	log.Debugf("Successfully generated CRL: %+v", req)
   207  	crl, err := util.B64Decode(result.CRL)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	return &api.GenCRLResponse{CRL: crl}, nil
   212  }
   213  
   214  // GetCRI gets Idemix credential revocation information (CRI)
   215  func (i *Identity) GetCRI(req *api.GetCRIRequest) (*api.GetCRIResponse, error) {
   216  	log.Debugf("Entering identity.GetCRI %+v", req)
   217  	reqBody, err := util.Marshal(req, "GetCRIRequest")
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  	var result api.GetCRIResponse
   222  	err = i.Post("idemix/cri", reqBody, &result, nil)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	log.Debugf("Successfully generated CRI: %+v", req)
   227  	return &result, nil
   228  }
   229  
   230  // GetIdentity returns information about the requested identity
   231  func (i *Identity) GetIdentity(id, caname string) (*api.GetIDResponse, error) {
   232  	log.Debugf("Entering identity.GetIdentity %s", id)
   233  	result := &api.GetIDResponse{}
   234  	err := i.Get(fmt.Sprintf("identities/%s", id), caname, result)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	log.Debugf("Successfully retrieved identity: %+v", result)
   240  	return result, nil
   241  }
   242  
   243  // GetAllIdentities returns all identities that the caller is authorized to see
   244  func (i *Identity) GetAllIdentities(caname string, cb func(*json.Decoder) error) error {
   245  	log.Debugf("Entering identity.GetAllIdentities")
   246  	queryParam := make(map[string]string)
   247  	queryParam["ca"] = caname
   248  	err := i.GetStreamResponse("identities", queryParam, "result.identities", cb)
   249  	if err != nil {
   250  		return err
   251  	}
   252  	log.Debugf("Successfully retrieved identities")
   253  	return nil
   254  }
   255  
   256  // AddIdentity adds a new identity to the server
   257  func (i *Identity) AddIdentity(req *api.AddIdentityRequest) (*api.IdentityResponse, error) {
   258  	log.Debugf("Entering identity.AddIdentity with request: %+v", req)
   259  	if req.ID == "" {
   260  		return nil, errors.New("Adding identity with no 'ID' set")
   261  	}
   262  
   263  	reqBody, err := util.Marshal(req, "addIdentity")
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  
   268  	// Send a post to the "identities" endpoint with req as body
   269  	result := &api.IdentityResponse{}
   270  	err = i.Post("identities", reqBody, result, nil)
   271  	if err != nil {
   272  		return nil, err
   273  	}
   274  
   275  	log.Debugf("Successfully added new identity '%s'", result.ID)
   276  	return result, nil
   277  }
   278  
   279  // ModifyIdentity modifies an existing identity on the server
   280  func (i *Identity) ModifyIdentity(req *api.ModifyIdentityRequest) (*api.IdentityResponse, error) {
   281  	log.Debugf("Entering identity.ModifyIdentity with request: %+v", req)
   282  	if req.ID == "" {
   283  		return nil, errors.New("Name of identity to be modified not specified")
   284  	}
   285  
   286  	reqBody, err := util.Marshal(req, "modifyIdentity")
   287  	if err != nil {
   288  		return nil, err
   289  	}
   290  
   291  	// Send a put to the "identities" endpoint with req as body
   292  	result := &api.IdentityResponse{}
   293  	err = i.Put(fmt.Sprintf("identities/%s", req.ID), reqBody, nil, result)
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  
   298  	log.Debugf("Successfully modified identity '%s'", result.ID)
   299  	return result, nil
   300  }
   301  
   302  // RemoveIdentity removes a new identity from the server
   303  func (i *Identity) RemoveIdentity(req *api.RemoveIdentityRequest) (*api.IdentityResponse, error) {
   304  	log.Debugf("Entering identity.RemoveIdentity with request: %+v", req)
   305  	id := req.ID
   306  	if id == "" {
   307  		return nil, errors.New("Name of the identity to removed is required")
   308  	}
   309  
   310  	// Send a delete to the "identities" endpoint id as a path parameter
   311  	result := &api.IdentityResponse{}
   312  	queryParam := make(map[string]string)
   313  	queryParam["force"] = strconv.FormatBool(req.Force)
   314  	queryParam["ca"] = req.CAName
   315  	err := i.Delete(fmt.Sprintf("identities/%s", id), result, queryParam)
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  
   320  	log.Debugf("Successfully removed identity: %s", id)
   321  	return result, nil
   322  }
   323  
   324  // GetAffiliation returns information about the requested affiliation
   325  func (i *Identity) GetAffiliation(affiliation, caname string) (*api.AffiliationResponse, error) {
   326  	log.Debugf("Entering identity.GetAffiliation %+v", affiliation)
   327  	result := &api.AffiliationResponse{}
   328  	err := i.Get(fmt.Sprintf("affiliations/%s", affiliation), caname, result)
   329  	if err != nil {
   330  		return nil, err
   331  	}
   332  	log.Debugf("Successfully retrieved affiliation: %+v", result)
   333  	return result, nil
   334  }
   335  
   336  // GetAllAffiliations returns all affiliations that the caller is authorized to see
   337  func (i *Identity) GetAllAffiliations(caname string) (*api.AffiliationResponse, error) {
   338  	log.Debugf("Entering identity.GetAllAffiliations")
   339  	result := &api.AffiliationResponse{}
   340  	err := i.Get("affiliations", caname, result)
   341  	if err != nil {
   342  		return nil, err
   343  	}
   344  	log.Debug("Successfully retrieved affiliations")
   345  	return result, nil
   346  }
   347  
   348  // AddAffiliation adds a new affiliation to the server
   349  func (i *Identity) AddAffiliation(req *api.AddAffiliationRequest) (*api.AffiliationResponse, error) {
   350  	log.Debugf("Entering identity.AddAffiliation with request: %+v", req)
   351  	if req.Name == "" {
   352  		return nil, errors.New("Affiliation to add was not specified")
   353  	}
   354  
   355  	reqBody, err := util.Marshal(req, "addAffiliation")
   356  	if err != nil {
   357  		return nil, err
   358  	}
   359  
   360  	// Send a post to the "affiliations" endpoint with req as body
   361  	result := &api.AffiliationResponse{}
   362  	queryParam := make(map[string]string)
   363  	queryParam["force"] = strconv.FormatBool(req.Force)
   364  	err = i.Post("affiliations", reqBody, result, queryParam)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  
   369  	log.Debugf("Successfully added new affiliation")
   370  	return result, nil
   371  }
   372  
   373  // ModifyAffiliation renames an existing affiliation on the server
   374  func (i *Identity) ModifyAffiliation(req *api.ModifyAffiliationRequest) (*api.AffiliationResponse, error) {
   375  	log.Debugf("Entering identity.ModifyAffiliation with request: %+v", req)
   376  	modifyAff := req.Name
   377  	if modifyAff == "" {
   378  		return nil, errors.New("Affiliation to modify was not specified")
   379  	}
   380  
   381  	if req.NewName == "" {
   382  		return nil, errors.New("New affiliation not specified")
   383  	}
   384  
   385  	reqBody, err := util.Marshal(req, "modifyIdentity")
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  
   390  	// Send a put to the "affiliations" endpoint with req as body
   391  	result := &api.AffiliationResponse{}
   392  	queryParam := make(map[string]string)
   393  	queryParam["force"] = strconv.FormatBool(req.Force)
   394  	err = i.Put(fmt.Sprintf("affiliations/%s", modifyAff), reqBody, queryParam, result)
   395  	if err != nil {
   396  		return nil, err
   397  	}
   398  
   399  	log.Debugf("Successfully modified affiliation")
   400  	return result, nil
   401  }
   402  
   403  // RemoveAffiliation removes an existing affiliation from the server
   404  func (i *Identity) RemoveAffiliation(req *api.RemoveAffiliationRequest) (*api.AffiliationResponse, error) {
   405  	log.Debugf("Entering identity.RemoveAffiliation with request: %+v", req)
   406  	removeAff := req.Name
   407  	if removeAff == "" {
   408  		return nil, errors.New("Affiliation to remove was not specified")
   409  	}
   410  
   411  	// Send a delete to the "affiliations" endpoint with the affiliation as a path parameter
   412  	result := &api.AffiliationResponse{}
   413  	queryParam := make(map[string]string)
   414  	queryParam["force"] = strconv.FormatBool(req.Force)
   415  	queryParam["ca"] = req.CAName
   416  	err := i.Delete(fmt.Sprintf("affiliations/%s", removeAff), result, queryParam)
   417  	if err != nil {
   418  		return nil, err
   419  	}
   420  
   421  	log.Debugf("Successfully removed affiliation")
   422  	return result, nil
   423  }
   424  
   425  // GetCertificates returns all certificates that the caller is authorized to see
   426  func (i *Identity) GetCertificates(req *api.GetCertificatesRequest, cb func(*json.Decoder) error) error {
   427  	log.Debugf("Entering identity.GetCertificates, sending request: %+v", req)
   428  
   429  	queryParam := make(map[string]string)
   430  	queryParam["id"] = req.ID
   431  	queryParam["aki"] = req.AKI
   432  	queryParam["serial"] = req.Serial
   433  	queryParam["revoked_start"] = req.Revoked.StartTime
   434  	queryParam["revoked_end"] = req.Revoked.EndTime
   435  	queryParam["expired_start"] = req.Expired.StartTime
   436  	queryParam["expired_end"] = req.Expired.EndTime
   437  	queryParam["notrevoked"] = strconv.FormatBool(req.NotRevoked)
   438  	queryParam["notexpired"] = strconv.FormatBool(req.NotExpired)
   439  	queryParam["ca"] = req.CAName
   440  	err := i.GetStreamResponse("certificates", queryParam, "result.certs", cb)
   441  	if err != nil {
   442  		return err
   443  	}
   444  
   445  	log.Debugf("Successfully completed getting certificates request")
   446  	return nil
   447  }
   448  
   449  // Store writes my identity info to disk
   450  func (i *Identity) Store() error {
   451  	if i.client == nil {
   452  		return errors.New("An identity with no client may not be stored")
   453  	}
   454  	for _, cred := range i.creds {
   455  		err := cred.Store()
   456  		if err != nil {
   457  			return err
   458  		}
   459  	}
   460  	return nil
   461  }
   462  
   463  // Get sends a get request to an endpoint
   464  func (i *Identity) Get(endpoint, caname string, result interface{}) error {
   465  	req, err := i.client.newGet(endpoint)
   466  	if err != nil {
   467  		return err
   468  	}
   469  	if caname != "" {
   470  		addQueryParm(req, "ca", caname)
   471  	}
   472  	err = i.addTokenAuthHdr(req, nil)
   473  	if err != nil {
   474  		return err
   475  	}
   476  	return i.client.SendReq(req, result)
   477  }
   478  
   479  // GetStreamResponse sends a request to an endpoint and streams the response
   480  func (i *Identity) GetStreamResponse(endpoint string, queryParam map[string]string, stream string, cb func(*json.Decoder) error) error {
   481  	req, err := i.client.newGet(endpoint)
   482  	if err != nil {
   483  		return err
   484  	}
   485  	if queryParam != nil {
   486  		for key, value := range queryParam {
   487  			if value != "" {
   488  				addQueryParm(req, key, value)
   489  			}
   490  		}
   491  	}
   492  	err = i.addTokenAuthHdr(req, nil)
   493  	if err != nil {
   494  		return err
   495  	}
   496  	return i.client.StreamResponse(req, stream, cb)
   497  }
   498  
   499  // Put sends a put request to an endpoint
   500  func (i *Identity) Put(endpoint string, reqBody []byte, queryParam map[string]string, result interface{}) error {
   501  	req, err := i.client.newPut(endpoint, reqBody)
   502  	if err != nil {
   503  		return err
   504  	}
   505  	if queryParam != nil {
   506  		for key, value := range queryParam {
   507  			addQueryParm(req, key, value)
   508  		}
   509  	}
   510  	err = i.addTokenAuthHdr(req, reqBody)
   511  	if err != nil {
   512  		return err
   513  	}
   514  	return i.client.SendReq(req, result)
   515  }
   516  
   517  // Delete sends a delete request to an endpoint
   518  func (i *Identity) Delete(endpoint string, result interface{}, queryParam map[string]string) error {
   519  	req, err := i.client.newDelete(endpoint)
   520  	if err != nil {
   521  		return err
   522  	}
   523  	if queryParam != nil {
   524  		for key, value := range queryParam {
   525  			addQueryParm(req, key, value)
   526  		}
   527  	}
   528  	err = i.addTokenAuthHdr(req, nil)
   529  	if err != nil {
   530  		return err
   531  	}
   532  	return i.client.SendReq(req, result)
   533  }
   534  
   535  // Post sends arbitrary request body (reqBody) to an endpoint.
   536  // This adds an authorization header which contains the signature
   537  // of this identity over the body and non-signature part of the authorization header.
   538  // The return value is the body of the response.
   539  func (i *Identity) Post(endpoint string, reqBody []byte, result interface{}, queryParam map[string]string) error {
   540  	req, err := i.client.newPost(endpoint, reqBody)
   541  	if err != nil {
   542  		return err
   543  	}
   544  	if queryParam != nil {
   545  		for key, value := range queryParam {
   546  			addQueryParm(req, key, value)
   547  		}
   548  	}
   549  	err = i.addTokenAuthHdr(req, reqBody)
   550  	if err != nil {
   551  		return err
   552  	}
   553  	return i.client.SendReq(req, result)
   554  }
   555  
   556  func (i *Identity) addTokenAuthHdr(req *http.Request, body []byte) error {
   557  	log.Debug("Adding token-based authorization header")
   558  	var token string
   559  	var err error
   560  	for _, cred := range i.creds {
   561  		token, err = cred.CreateToken(req, body)
   562  		if err != nil {
   563  			return errors.WithMessage(err, "Failed to add token authorization header")
   564  		}
   565  		break
   566  	}
   567  	req.Header.Set("authorization", token)
   568  	return nil
   569  }