github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/identity.go (about)

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