github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/lib/servercertificates.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  	"fmt"
    11  	"os"
    12  
    13  	log "gitee.com/zhaochuninhefei/zcgolog/zclog"
    14  	http "github.com/hxx258456/ccgo/gmhttp"
    15  	"github.com/hxx258456/fabric-ca-gm/internal/pkg/util"
    16  	"github.com/hxx258456/fabric-ca-gm/lib/caerrors"
    17  	"github.com/hxx258456/fabric-ca-gm/lib/server/certificaterequest"
    18  	cadbuser "github.com/hxx258456/fabric-ca-gm/lib/server/user"
    19  	"github.com/pkg/errors"
    20  )
    21  
    22  type certPEM struct {
    23  	PEM string `db:"pem"`
    24  }
    25  
    26  func newCertificateEndpoint(s *Server) *serverEndpoint {
    27  	return &serverEndpoint{
    28  		Path:      "certificates",
    29  		Methods:   []string{"GET", "DELETE"},
    30  		Handler:   certificatesHandler,
    31  		Server:    s,
    32  		successRC: 200,
    33  	}
    34  }
    35  
    36  func certificatesHandler(ctx *serverRequestContextImpl) (interface{}, error) {
    37  	// Process Request
    38  	err := processCertificateRequest(ctx)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return nil, nil
    43  }
    44  
    45  // processCertificateRequest will process the certificate request
    46  func processCertificateRequest(ctx ServerRequestContext) error {
    47  	log.Debug("Processing certificate request")
    48  	var err error
    49  
    50  	// Authenticate
    51  	_, err = ctx.TokenAuthentication()
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	// Perform authority checks to make sure that caller has the correct
    57  	// set of attributes to manage certificates
    58  	err = authChecks(ctx)
    59  	if err != nil {
    60  		return err
    61  	}
    62  
    63  	method := ctx.GetReq().Method
    64  	switch method {
    65  	case "GET":
    66  		return processGetCertificateRequest(ctx)
    67  	case "DELETE":
    68  		return errors.New("DELETE Not Implemented")
    69  	default:
    70  		return errors.Errorf("Invalid request: %s", method)
    71  	}
    72  }
    73  
    74  // authChecks verifies that the caller has either attribute "hf.Registrar.Roles"
    75  // or "hf.Revoker" with a value of true
    76  func authChecks(ctx ServerRequestContext) error {
    77  	log.Debug("Performing attribute authorization checks for certificates endpoint")
    78  
    79  	caller, err := ctx.GetCaller()
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	_, err = caller.GetAttribute("hf.Registrar.Roles")
    85  	if err != nil {
    86  		err = ctx.HasRole("hf.Revoker")
    87  		if err != nil {
    88  			return caerrors.NewAuthorizationErr(caerrors.ErrAuthorizationFailure, "Caller does not posses either hf.Registrar.Roles or hf.Revoker attribute")
    89  		}
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  func processGetCertificateRequest(ctx ServerRequestContext) error {
    96  	log.Debug("Processing GET certificate request")
    97  	var err error
    98  
    99  	req, err := certificaterequest.NewCertificateRequest(ctx)
   100  	if err != nil {
   101  		return caerrors.NewHTTPErr(400, caerrors.ErrGettingCert, "Invalid Request: %s", err)
   102  	}
   103  
   104  	// Execute DB query and stream response
   105  	err = getCertificates(ctx, req)
   106  	if err != nil {
   107  		return err
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  // getCertificates executes the DB query and streams the results to client
   114  func getCertificates(ctx ServerRequestContext, req *certificaterequest.Impl) error {
   115  	w := ctx.GetResp()
   116  	flusher, _ := w.(http.Flusher)
   117  
   118  	caller, err := ctx.GetCaller()
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	// Execute DB query
   124  	rows, err := ctx.GetCertificates(req, cadbuser.GetAffiliation(caller))
   125  	if err != nil {
   126  		return err
   127  	}
   128  	defer rows.Close()
   129  
   130  	// Get the number of certificates to return back to client in a chunk based on the environment variable
   131  	// If environment variable not set, default to 100 certificates
   132  	numCerts, err := ctx.ChunksToDeliver(os.Getenv("FABRIC_CA_SERVER_MAX_CERTS_PER_CHUNK"))
   133  	if err != nil {
   134  		return err
   135  	}
   136  	log.Debugf("Number of certs to be delivered in each chunk: %d", numCerts)
   137  
   138  	w.Write([]byte(`{"certs":[`))
   139  
   140  	rowNumber := 0
   141  	for rows.Next() {
   142  		rowNumber++
   143  		var cert certPEM
   144  		err := rows.StructScan(&cert)
   145  		if err != nil {
   146  			return caerrors.NewHTTPErr(500, caerrors.ErrGettingCert, "Failed to get read row: %s", err)
   147  		}
   148  
   149  		if rowNumber > 1 {
   150  			w.Write([]byte(","))
   151  		}
   152  
   153  		resp, err := util.Marshal(cert, "certificate")
   154  		if err != nil {
   155  			return caerrors.NewHTTPErr(500, caerrors.ErrGettingCert, "Failed to marshal certificate: %s", err)
   156  		}
   157  		w.Write(resp)
   158  
   159  		// If hit the number of identities requested then flush
   160  		if rowNumber%numCerts == 0 {
   161  			flusher.Flush() // Trigger "chunked" encoding and send a chunk...
   162  		}
   163  	}
   164  
   165  	log.Debug("Number of certificates found: ", rowNumber)
   166  
   167  	// Close the JSON object
   168  	caname := ctx.GetQueryParm("ca")
   169  	w.Write([]byte(fmt.Sprintf("], \"caname\":\"%s\"}", caname)))
   170  	flusher.Flush()
   171  
   172  	return nil
   173  }