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