github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/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  	"strconv"
    13  
    14  	log "gitee.com/zhaochuninhefei/zcgolog/zclog"
    15  	http "github.com/hxx258456/ccgo/gmhttp"
    16  	"github.com/hxx258456/fabric-ca-gm/internal/pkg/api"
    17  	"github.com/hxx258456/fabric-ca-gm/internal/pkg/util"
    18  	"github.com/hxx258456/fabric-ca-gm/lib/client/credential"
    19  	"github.com/hxx258456/fabric-ca-gm/lib/client/credential/idemix"
    20  	"github.com/hxx258456/fabric-ca-gm/lib/client/credential/x509"
    21  	"github.com/hxx258456/fabric-gm/bccsp"
    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  	var (
   135  		key    bccsp.Key
   136  		csrPEM []byte
   137  		err    error
   138  	)
   139  	if req.CSR != nil && req.CSR.KeyRequest != nil {
   140  		if req.CSR.KeyRequest.ReuseKey {
   141  			val, err := i.GetX509Credential().Val()
   142  			if err != nil {
   143  				return nil, err
   144  			}
   145  			key = val.(*x509.Signer).Key()
   146  			csrPEM, key, err = i.client.GenCSRUsingKey(req.CSR, i.GetName(), key)
   147  			if err != nil {
   148  				return nil, err
   149  			}
   150  		}
   151  	}
   152  
   153  	if csrPEM == nil {
   154  		csrPEM, key, err = i.client.GenCSR(req.CSR, i.GetName())
   155  		if err != nil {
   156  			return nil, err
   157  		}
   158  	}
   159  
   160  	reqNet := &api.ReenrollmentRequestNet{
   161  		CAName:   req.CAName,
   162  		AttrReqs: req.AttrReqs,
   163  	}
   164  
   165  	// Get the body of the request
   166  	if req.CSR != nil {
   167  		reqNet.SignRequest.Hosts = req.CSR.Hosts
   168  	}
   169  	reqNet.SignRequest.Request = string(csrPEM)
   170  	reqNet.SignRequest.Profile = req.Profile
   171  	reqNet.SignRequest.Label = req.Label
   172  
   173  	body, err := util.Marshal(reqNet, "SignRequest")
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	var result api.EnrollmentResponseNet
   178  	err = i.Post("reenroll", body, &result, nil)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	return i.client.newEnrollmentResponse(&result, i.GetName(), key)
   183  }
   184  
   185  // Revoke the identity associated with 'id'
   186  func (i *Identity) Revoke(req *api.RevocationRequest) (*api.RevocationResponse, error) {
   187  	log.Debugf("Entering identity.Revoke %+v", req)
   188  	reqBody, err := util.Marshal(req, "RevocationRequest")
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	var result revocationResponseNet
   193  	err = i.Post("revoke", reqBody, &result, nil)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	log.Debugf("Successfully revoked certificates: %+v", req)
   198  	crl, err := util.B64Decode(result.CRL)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	return &api.RevocationResponse{RevokedCerts: result.RevokedCerts, CRL: crl}, nil
   203  }
   204  
   205  // RevokeSelf revokes the current identity and all certificates
   206  func (i *Identity) RevokeSelf() (*api.RevocationResponse, error) {
   207  	name := i.GetName()
   208  	log.Debugf("RevokeSelf %s", name)
   209  	req := &api.RevocationRequest{
   210  		Name: name,
   211  	}
   212  	return i.Revoke(req)
   213  }
   214  
   215  // GenCRL generates CRL
   216  func (i *Identity) GenCRL(req *api.GenCRLRequest) (*api.GenCRLResponse, error) {
   217  	log.Debugf("Entering identity.GenCRL %+v", req)
   218  	reqBody, err := util.Marshal(req, "GenCRLRequest")
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	var result genCRLResponseNet
   223  	err = i.Post("gencrl", reqBody, &result, nil)
   224  	if err != nil {
   225  		return nil, err
   226  	}
   227  	log.Debugf("Successfully generated CRL: %+v", req)
   228  	crl, err := util.B64Decode(result.CRL)
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  	return &api.GenCRLResponse{CRL: crl}, nil
   233  }
   234  
   235  // GetCRI gets Idemix credential revocation information (CRI)
   236  func (i *Identity) GetCRI(req *api.GetCRIRequest) (*api.GetCRIResponse, error) {
   237  	log.Debugf("Entering identity.GetCRI %+v", req)
   238  	reqBody, err := util.Marshal(req, "GetCRIRequest")
   239  	if err != nil {
   240  		return nil, err
   241  	}
   242  	var result api.GetCRIResponse
   243  	err = i.Post("idemix/cri", reqBody, &result, nil)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	log.Debugf("Successfully generated CRI: %+v", req)
   248  	return &result, nil
   249  }
   250  
   251  // GetIdentity returns information about the requested identity
   252  func (i *Identity) GetIdentity(id, caname string) (*api.GetIDResponse, error) {
   253  	log.Debugf("Entering identity.GetIdentity %s", id)
   254  	result := &api.GetIDResponse{}
   255  	err := i.Get(fmt.Sprintf("identities/%s", id), caname, result)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	log.Debugf("Successfully retrieved identity: %+v", result)
   261  	return result, nil
   262  }
   263  
   264  // GetAllIdentities returns all identities that the caller is authorized to see
   265  func (i *Identity) GetAllIdentities(caname string, cb func(*json.Decoder) error) error {
   266  	log.Debugf("Entering identity.GetAllIdentities")
   267  	queryParam := make(map[string]string)
   268  	queryParam["ca"] = caname
   269  	err := i.GetStreamResponse("identities", queryParam, "result.identities", cb)
   270  	if err != nil {
   271  		return err
   272  	}
   273  	log.Debugf("Successfully retrieved identities")
   274  	return nil
   275  }
   276  
   277  // AddIdentity adds a new identity to the server
   278  func (i *Identity) AddIdentity(req *api.AddIdentityRequest) (*api.IdentityResponse, error) {
   279  	log.Debugf("Entering identity.AddIdentity with request: %+v", req)
   280  	if req.ID == "" {
   281  		return nil, errors.New("Adding identity with no 'ID' set")
   282  	}
   283  
   284  	reqBody, err := util.Marshal(req, "addIdentity")
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  
   289  	// Send a post to the "identities" endpoint with req as body
   290  	result := &api.IdentityResponse{}
   291  	err = i.Post("identities", reqBody, result, nil)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  
   296  	log.Debugf("Successfully added new identity '%s'", result.ID)
   297  	return result, nil
   298  }
   299  
   300  // ModifyIdentity modifies an existing identity on the server
   301  func (i *Identity) ModifyIdentity(req *api.ModifyIdentityRequest) (*api.IdentityResponse, error) {
   302  	log.Debugf("Entering identity.ModifyIdentity with request: %+v", req)
   303  	if req.ID == "" {
   304  		return nil, errors.New("Name of identity to be modified not specified")
   305  	}
   306  
   307  	reqBody, err := util.Marshal(req, "modifyIdentity")
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  
   312  	// Send a put to the "identities" endpoint with req as body
   313  	result := &api.IdentityResponse{}
   314  	err = i.Put(fmt.Sprintf("identities/%s", req.ID), reqBody, nil, result)
   315  	if err != nil {
   316  		return nil, err
   317  	}
   318  
   319  	log.Debugf("Successfully modified identity '%s'", result.ID)
   320  	return result, nil
   321  }
   322  
   323  // RemoveIdentity removes a new identity from the server
   324  func (i *Identity) RemoveIdentity(req *api.RemoveIdentityRequest) (*api.IdentityResponse, error) {
   325  	log.Debugf("Entering identity.RemoveIdentity with request: %+v", req)
   326  	id := req.ID
   327  	if id == "" {
   328  		return nil, errors.New("Name of the identity to removed is required")
   329  	}
   330  
   331  	// Send a delete to the "identities" endpoint id as a path parameter
   332  	result := &api.IdentityResponse{}
   333  	queryParam := make(map[string]string)
   334  	queryParam["force"] = strconv.FormatBool(req.Force)
   335  	queryParam["ca"] = req.CAName
   336  	err := i.Delete(fmt.Sprintf("identities/%s", id), result, queryParam)
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	log.Debugf("Successfully removed identity: %s", id)
   342  	return result, nil
   343  }
   344  
   345  // GetAffiliation returns information about the requested affiliation
   346  func (i *Identity) GetAffiliation(affiliation, caname string) (*api.AffiliationResponse, error) {
   347  	log.Debugf("Entering identity.GetAffiliation %+v", affiliation)
   348  	result := &api.AffiliationResponse{}
   349  	err := i.Get(fmt.Sprintf("affiliations/%s", affiliation), caname, result)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  	log.Debugf("Successfully retrieved affiliation: %+v", result)
   354  	return result, nil
   355  }
   356  
   357  // GetAllAffiliations returns all affiliations that the caller is authorized to see
   358  func (i *Identity) GetAllAffiliations(caname string) (*api.AffiliationResponse, error) {
   359  	log.Debugf("Entering identity.GetAllAffiliations")
   360  	result := &api.AffiliationResponse{}
   361  	err := i.Get("affiliations", caname, result)
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  	log.Debug("Successfully retrieved affiliations")
   366  	return result, nil
   367  }
   368  
   369  // AddAffiliation adds a new affiliation to the server
   370  func (i *Identity) AddAffiliation(req *api.AddAffiliationRequest) (*api.AffiliationResponse, error) {
   371  	log.Debugf("Entering identity.AddAffiliation with request: %+v", req)
   372  	if req.Name == "" {
   373  		return nil, errors.New("Affiliation to add was not specified")
   374  	}
   375  
   376  	reqBody, err := util.Marshal(req, "addAffiliation")
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  
   381  	// Send a post to the "affiliations" endpoint with req as body
   382  	result := &api.AffiliationResponse{}
   383  	queryParam := make(map[string]string)
   384  	queryParam["force"] = strconv.FormatBool(req.Force)
   385  	err = i.Post("affiliations", reqBody, result, queryParam)
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  
   390  	log.Debugf("Successfully added new affiliation")
   391  	return result, nil
   392  }
   393  
   394  // ModifyAffiliation renames an existing affiliation on the server
   395  func (i *Identity) ModifyAffiliation(req *api.ModifyAffiliationRequest) (*api.AffiliationResponse, error) {
   396  	log.Debugf("Entering identity.ModifyAffiliation with request: %+v", req)
   397  	modifyAff := req.Name
   398  	if modifyAff == "" {
   399  		return nil, errors.New("Affiliation to modify was not specified")
   400  	}
   401  
   402  	if req.NewName == "" {
   403  		return nil, errors.New("New affiliation not specified")
   404  	}
   405  
   406  	reqBody, err := util.Marshal(req, "modifyIdentity")
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  
   411  	// Send a put to the "affiliations" endpoint with req as body
   412  	result := &api.AffiliationResponse{}
   413  	queryParam := make(map[string]string)
   414  	queryParam["force"] = strconv.FormatBool(req.Force)
   415  	err = i.Put(fmt.Sprintf("affiliations/%s", modifyAff), reqBody, queryParam, result)
   416  	if err != nil {
   417  		return nil, err
   418  	}
   419  
   420  	log.Debugf("Successfully modified affiliation")
   421  	return result, nil
   422  }
   423  
   424  // RemoveAffiliation removes an existing affiliation from the server
   425  func (i *Identity) RemoveAffiliation(req *api.RemoveAffiliationRequest) (*api.AffiliationResponse, error) {
   426  	log.Debugf("Entering identity.RemoveAffiliation with request: %+v", req)
   427  	removeAff := req.Name
   428  	if removeAff == "" {
   429  		return nil, errors.New("Affiliation to remove was not specified")
   430  	}
   431  
   432  	// Send a delete to the "affiliations" endpoint with the affiliation as a path parameter
   433  	result := &api.AffiliationResponse{}
   434  	queryParam := make(map[string]string)
   435  	queryParam["force"] = strconv.FormatBool(req.Force)
   436  	queryParam["ca"] = req.CAName
   437  	err := i.Delete(fmt.Sprintf("affiliations/%s", removeAff), result, queryParam)
   438  	if err != nil {
   439  		return nil, err
   440  	}
   441  
   442  	log.Debugf("Successfully removed affiliation")
   443  	return result, nil
   444  }
   445  
   446  // GetCertificates returns all certificates that the caller is authorized to see
   447  func (i *Identity) GetCertificates(req *api.GetCertificatesRequest, cb func(*json.Decoder) error) error {
   448  	log.Debugf("Entering identity.GetCertificates, sending request: %+v", req)
   449  
   450  	queryParam := make(map[string]string)
   451  	queryParam["id"] = req.ID
   452  	queryParam["aki"] = req.AKI
   453  	queryParam["serial"] = req.Serial
   454  	queryParam["revoked_start"] = req.Revoked.StartTime
   455  	queryParam["revoked_end"] = req.Revoked.EndTime
   456  	queryParam["expired_start"] = req.Expired.StartTime
   457  	queryParam["expired_end"] = req.Expired.EndTime
   458  	queryParam["notrevoked"] = strconv.FormatBool(req.NotRevoked)
   459  	queryParam["notexpired"] = strconv.FormatBool(req.NotExpired)
   460  	queryParam["ca"] = req.CAName
   461  	err := i.GetStreamResponse("certificates", queryParam, "result.certs", cb)
   462  	if err != nil {
   463  		return err
   464  	}
   465  
   466  	log.Debugf("Successfully completed getting certificates request")
   467  	return nil
   468  }
   469  
   470  // Store writes my identity info to disk
   471  func (i *Identity) Store() error {
   472  	if i.client == nil {
   473  		return errors.New("An identity with no client may not be stored")
   474  	}
   475  	for _, cred := range i.creds {
   476  		err := cred.Store()
   477  		if err != nil {
   478  			return err
   479  		}
   480  	}
   481  	return nil
   482  }
   483  
   484  // Get sends a get request to an endpoint
   485  func (i *Identity) Get(endpoint, caname string, result interface{}) error {
   486  	req, err := i.client.newGet(endpoint)
   487  	if err != nil {
   488  		return err
   489  	}
   490  	if caname != "" {
   491  		addQueryParm(req, "ca", caname)
   492  	}
   493  	err = i.addTokenAuthHdr(req, nil)
   494  	if err != nil {
   495  		return err
   496  	}
   497  	return i.client.SendReq(req, result)
   498  }
   499  
   500  // GetStreamResponse sends a request to an endpoint and streams the response
   501  func (i *Identity) GetStreamResponse(endpoint string, queryParam map[string]string, stream string, cb func(*json.Decoder) error) error {
   502  	req, err := i.client.newGet(endpoint)
   503  	if err != nil {
   504  		return err
   505  	}
   506  	for key, value := range queryParam {
   507  		if value != "" {
   508  			addQueryParm(req, key, value)
   509  		}
   510  	}
   511  	err = i.addTokenAuthHdr(req, nil)
   512  	if err != nil {
   513  		return err
   514  	}
   515  	return i.client.StreamResponse(req, stream, cb)
   516  }
   517  
   518  // Put sends a put request to an endpoint
   519  func (i *Identity) Put(endpoint string, reqBody []byte, queryParam map[string]string, result interface{}) error {
   520  	req, err := i.client.newPut(endpoint, reqBody)
   521  	if err != nil {
   522  		return err
   523  	}
   524  	for key, value := range queryParam {
   525  		addQueryParm(req, key, value)
   526  	}
   527  	err = i.addTokenAuthHdr(req, reqBody)
   528  	if err != nil {
   529  		return err
   530  	}
   531  	return i.client.SendReq(req, result)
   532  }
   533  
   534  // Delete sends a delete request to an endpoint
   535  func (i *Identity) Delete(endpoint string, result interface{}, queryParam map[string]string) error {
   536  	req, err := i.client.newDelete(endpoint)
   537  	if err != nil {
   538  		return err
   539  	}
   540  	for key, value := range queryParam {
   541  		addQueryParm(req, key, value)
   542  	}
   543  	err = i.addTokenAuthHdr(req, nil)
   544  	if err != nil {
   545  		return err
   546  	}
   547  	return i.client.SendReq(req, result)
   548  }
   549  
   550  // Post sends arbitrary request body (reqBody) to an endpoint.
   551  // This adds an authorization header which contains the signature
   552  // of this identity over the body and non-signature part of the authorization header.
   553  // The return value is the body of the response.
   554  func (i *Identity) Post(endpoint string, reqBody []byte, result interface{}, queryParam map[string]string) error {
   555  	req, err := i.client.newPost(endpoint, reqBody)
   556  	if err != nil {
   557  		return err
   558  	}
   559  	for key, value := range queryParam {
   560  		addQueryParm(req, key, value)
   561  	}
   562  	err = i.addTokenAuthHdr(req, reqBody)
   563  	if err != nil {
   564  		return err
   565  	}
   566  	return i.client.SendReq(req, result)
   567  }
   568  
   569  func (i *Identity) addTokenAuthHdr(req *http.Request, body []byte) error {
   570  	log.Debug("Adding token-based authorization header")
   571  	if len(i.creds) == 0 {
   572  		return nil
   573  	}
   574  	cred := i.creds[0]
   575  	token, err := cred.CreateToken(req, body)
   576  	if err != nil {
   577  		return errors.WithMessage(err, "Failed to add token authorization header")
   578  	}
   579  	req.Header.Set("authorization", token)
   580  	return nil
   581  }