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