Skip to content

Commit

Permalink
Expose new Admin endpoint on orderer for the channel participation API (
Browse files Browse the repository at this point in the history
#1939)

* Split out common server logic for http endpoints

Move the common logic for http server/handler and TLS
authentication used by the operations.System into a
separate fabhttp.Server and refactor the operations.System
to embed the server. This is being done to allow reuse of
the common code for the orderer Admin endpoint, which will
host the Channel Participation API.

FAB-18246

Signed-off-by: Will Lahti <wtlahti@us.ibm.com>

* Expose new Admin endpoint on orderer

Move the channel participation API to use this
endpoint.

FAB-18246 #done

Signed-off-by: Will Lahti <wtlahti@us.ibm.com>
  • Loading branch information
wlahti authored Oct 26, 2020
1 parent 60b5053 commit d59af2c
Show file tree
Hide file tree
Showing 16 changed files with 716 additions and 155 deletions.
74 changes: 74 additions & 0 deletions common/fabhttp/fabhttp_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Copyright IBM Corp All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package fabhttp_test

import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"net/http"
"path/filepath"
"testing"

"github.com/hyperledger/fabric/common/crypto/tlsgen"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestFabHTTP(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "FabHTTP Suite")
}

func generateCertificates(tempDir string) {
serverCA, err := tlsgen.NewCA()
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(tempDir, "server-ca.pem"), serverCA.CertBytes(), 0640)
Expect(err).NotTo(HaveOccurred())
serverKeyPair, err := serverCA.NewServerCertKeyPair("127.0.0.1")
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(tempDir, "server-cert.pem"), serverKeyPair.Cert, 0640)
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(tempDir, "server-key.pem"), serverKeyPair.Key, 0640)
Expect(err).NotTo(HaveOccurred())

clientCA, err := tlsgen.NewCA()
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(tempDir, "client-ca.pem"), clientCA.CertBytes(), 0640)
Expect(err).NotTo(HaveOccurred())
clientKeyPair, err := clientCA.NewClientCertKeyPair()
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(tempDir, "client-cert.pem"), clientKeyPair.Cert, 0640)
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(tempDir, "client-key.pem"), clientKeyPair.Key, 0640)
Expect(err).NotTo(HaveOccurred())
}

func newHTTPClient(tlsDir string, withClientCert bool) *http.Client {
clientCertPool := x509.NewCertPool()
caCert, err := ioutil.ReadFile(filepath.Join(tlsDir, "server-ca.pem"))
Expect(err).NotTo(HaveOccurred())
clientCertPool.AppendCertsFromPEM(caCert)

tlsClientConfig := &tls.Config{
RootCAs: clientCertPool,
}
if withClientCert {
clientCert, err := tls.LoadX509KeyPair(
filepath.Join(tlsDir, "client-cert.pem"),
filepath.Join(tlsDir, "client-key.pem"),
)
Expect(err).NotTo(HaveOccurred())
tlsClientConfig.Certificates = []tls.Certificate{clientCert}
}

return &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsClientConfig,
},
}
}
115 changes: 115 additions & 0 deletions common/fabhttp/fakes/logger.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

144 changes: 144 additions & 0 deletions common/fabhttp/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
Copyright IBM Corp All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package fabhttp

import (
"context"
"crypto/tls"
"net"
"net/http"
"os"
"time"

"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/middleware"
)

//go:generate counterfeiter -o fakes/logger.go -fake-name Logger . Logger

type Logger interface {
Warn(args ...interface{})
Warnf(template string, args ...interface{})
}

type Options struct {
Logger Logger
ListenAddress string
TLS TLS
}

type Server struct {
logger Logger
options Options
httpServer *http.Server
mux *http.ServeMux
addr string
}

func NewServer(o Options) *Server {
logger := o.Logger
if logger == nil {
logger = flogging.MustGetLogger("fabhttp")
}

server := &Server{
logger: logger,
options: o,
}

server.initializeServer()

return server
}

func (s *Server) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
err := s.Start()
if err != nil {
return err
}

close(ready)

<-signals
return s.Stop()
}

func (s *Server) Start() error {
listener, err := s.Listen()
if err != nil {
return err
}
s.addr = listener.Addr().String()

go s.httpServer.Serve(listener)

return nil
}

func (s *Server) Stop() error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

return s.httpServer.Shutdown(ctx)
}

func (s *Server) initializeServer() {
s.mux = http.NewServeMux()
s.httpServer = &http.Server{
Addr: s.options.ListenAddress,
Handler: s.mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 2 * time.Minute,
}
}

func (s *Server) HandlerChain(h http.Handler, secure bool) http.Handler {
if secure {
return middleware.NewChain(middleware.RequireCert(), middleware.WithRequestID(util.GenerateUUID)).Handler(h)
}
return middleware.NewChain(middleware.WithRequestID(util.GenerateUUID)).Handler(h)
}

// RegisterHandler registers into the ServeMux a handler chain that borrows
// its security properties from the fabhttp.Server. This method is thread
// safe because ServeMux.Handle() is thread safe, and options are immutable.
// This method can be called either before or after Server.Start(). If the
// pattern exists the method panics.
func (s *Server) RegisterHandler(pattern string, handler http.Handler, secure bool) {
s.mux.Handle(
pattern,
s.HandlerChain(
handler,
secure,
),
)
}

func (s *Server) Listen() (net.Listener, error) {
listener, err := net.Listen("tcp", s.options.ListenAddress)
if err != nil {
return nil, err
}
tlsConfig, err := s.options.TLS.Config()
if err != nil {
return nil, err
}
if tlsConfig != nil {
listener = tls.NewListener(listener, tlsConfig)
}
return listener, nil
}

func (s *Server) Addr() string {
return s.addr
}

func (s *Server) Log(keyvals ...interface{}) error {
s.logger.Warn(keyvals...)
return nil
}
Loading

0 comments on commit d59af2c

Please sign in to comment.