Skip to content

Commit

Permalink
Remove global variables in lib
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-2012

This is the last change set pertaining to the cobra/viper restructure.
It removes all of the server-related global variables which were used
in the past.  The server is now implemented as a true library whose state
variables are in the server or server config objects

The primary changes are to pass the server object to all of the
server endpoint objects (i.e. those of the form serverXXXX.go) so that
they can reference the per-server state variables.
I also had to move some of the util.go funtions into server
so they had access to these per-server variables.

Change-Id: I1208542b6aedea30bedcad280808429622900aff
Signed-off-by: Keith Smith <bksmith@us.ibm.com>
  • Loading branch information
Keith Smith committed Mar 9, 2017
1 parent ee4f92a commit df922a1
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 217 deletions.
2 changes: 1 addition & 1 deletion lib/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func (c *Client) getURL(endpoint string) (string, error) {
if err != nil {
return "", err
}
rtn := fmt.Sprintf("%s/api/v1/cfssl/%s", nurl, endpoint)
rtn := fmt.Sprintf("%s/%s", nurl, endpoint)
return rtn, nil
}

Expand Down
131 changes: 72 additions & 59 deletions lib/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,6 @@ import (
_ "github.com/mattn/go-sqlite3" // import to support SQLite3
)

// FIXME: These variables are temporary and will be removed once
// the cobra/viper move is complete and we no longer support the fabric command.
// The correct way is to pass the Server object (and thus ServerConfig)
// to the endpoint handler constructors, thus using no global variables.
var (
EnrollSigner signer.Signer
UserRegistry spi.UserRegistry
MaxEnrollments int
MyCertDBAccessor *CertDBAccessor
CAKeyFile string
CACertFile string
MyCSP bccsp.BCCSP
)

const (
defaultDatabaseType = "sqlite3"
)
Expand Down Expand Up @@ -103,9 +89,8 @@ func (s *Server) Init(renew bool) (err error) {
if err != nil {
return err
}

MyCSP = factory.GetDefault()

// Initialize the Crypto Service Provider
s.csp = factory.GetDefault()
// Initialize key materials
err = s.initKeyMaterial(renew)
if err != nil {
Expand Down Expand Up @@ -140,10 +125,6 @@ func (s *Server) Start() (err error) {
return err
}

// TEMP
CAKeyFile = s.Config.CA.Keyfile
CACertFile = s.Config.CA.Certfile

// Register http handlers
s.registerHandlers()

Expand Down Expand Up @@ -343,15 +324,14 @@ func (s *Server) initDB() error {
var err error
var exists bool

MaxEnrollments = s.Config.Registry.MaxEnrollments

if db.Datasource == "" {
db.Datasource = "fabric-ca-server.db"
}

if db.Type == "" || db.Type == defaultDatabaseType {

db.Type = defaultDatabaseType

if db.Datasource == "" {
db.Datasource = "fabric-ca-server.db"
}

db.Datasource, err = util.MakeFileAbs(db.Datasource, s.HomeDir)
if err != nil {
return err
Expand Down Expand Up @@ -382,7 +362,6 @@ func (s *Server) initDB() error {

// Set the certificate DB accessor
s.certDBAccessor = NewCertDBAccessor(s.db)
MyCertDBAccessor = s.certDBAccessor

// Initialize the user registry.
// If LDAP is not configured, the fabric-ca server functions as a user
Expand Down Expand Up @@ -416,7 +395,6 @@ func (s *Server) initUserRegistry() error {
if ldapCfg.Enabled {
// Use LDAP for the user registry
s.registry, err = ldap.NewClient(ldapCfg)
UserRegistry = s.registry
log.Debugf("Initialized LDAP user registry; err=%s", err)
return err
}
Expand All @@ -425,7 +403,6 @@ func (s *Server) initUserRegistry() error {
dbAccessor := new(Accessor)
dbAccessor.SetDB(s.db)
s.registry = dbAccessor
UserRegistry = s.registry
log.Debug("Initialized DB user registry")
return nil
}
Expand Down Expand Up @@ -464,7 +441,6 @@ func (s *Server) initEnrollmentSigner() (err error) {
ForceRemote: c.Remote != "",
}
s.enrollSigner, err = universal.NewSigner(root, policy)
EnrollSigner = s.enrollSigner
if err != nil {
return err
}
Expand All @@ -477,42 +453,37 @@ func (s *Server) initEnrollmentSigner() (err error) {
// Register all endpoint handlers
func (s *Server) registerHandlers() {
s.mux = http.NewServeMux()
s.registerHandlerLog("register", NewRegisterHandler)
s.registerHandlerLog("enroll", NewEnrollHandler)
s.registerHandlerLog("reenroll", NewReenrollHandler)
s.registerHandlerLog("revoke", NewRevokeHandler)
s.registerHandlerLog("tcert", NewTCertHandler)
}

// Register an endpoint handler and log success or error
func (s *Server) registerHandlerLog(
path string,
getHandler func() (http.Handler, error)) {
err := s.registerHandler(path, getHandler)
if err != nil {
log.Warningf("Endpoint '%s' is disabled: %s", path, err)
} else {
log.Infof("Endpoint '%s' is enabled", path)
}
s.registerHandler("register", NewRegisterHandler, false, true)
s.registerHandler("enroll", NewEnrollHandler, true, false)
s.registerHandler("reenroll", NewReenrollHandler, true, false)
s.registerHandler("revoke", NewRevokeHandler, true, false)
s.registerHandler("tcert", NewTCertHandler, true, false)
}

// Register an endpoint handler and return an error if unsuccessful
// Register an endpoint handler
func (s *Server) registerHandler(
path string,
getHandler func() (http.Handler, error)) (err error) {
getHandler func(server *Server) (http.Handler, error),
basic bool,
token bool) {

var handler http.Handler

handler, err = getHandler()
if err != nil {
return fmt.Errorf("Endpoint '%s' is disabled: %s", path, err)
}
path, handler, err = NewAuthWrapper(path, handler, err)
handler, err := getHandler(s)
if err != nil {
return fmt.Errorf("Endpoint '%s' has been disabled: %s", path, err)
}
s.mux.Handle(path, handler)
return nil
log.Warningf("Endpoint '%s' is disabled: %s", path, err)
return
}
handler = &fcaAuthHandler{
server: s,
basic: basic,
token: token,
next: handler,
}
s.mux.Handle("/"+path, handler)
// TODO: Remove the following line once all SDKs stop using the prefixed paths
// See https://jira.hyperledger.org/browse/FAB-2597
s.mux.Handle("/api/v1/cfssl/"+path, handler)
}

// Starting listening and serving
Expand Down Expand Up @@ -675,6 +646,11 @@ func (s *Server) addAffiliation(path, parentPath string) error {
return s.registry.InsertAffiliation(path, parentPath)
}

// CertDBAccessor returns the certificate DB accessor for server
func (s *Server) CertDBAccessor() *CertDBAccessor {
return s.certDBAccessor
}

func (s *Server) convertAttrs(inAttrs map[string]string) []api.Attribute {
outAttrs := make([]api.Attribute, 0)
for name, value := range inAttrs {
Expand Down Expand Up @@ -725,6 +701,43 @@ func (s *Server) makeFileNamesAbsolute() error {
return nil
}

// userHasAttribute returns nil if the user has the attribute, or an
// appropriate error if the user does not have this attribute.
func (s *Server) userHasAttribute(username, attrname string) error {
val, err := s.getUserAttrValue(username, attrname)
if err != nil {
return err
}
if val == "" {
return fmt.Errorf("user '%s' does not have attribute '%s'", username, attrname)
}
return nil
}

// getUserAttrValue returns a user's value for an attribute
func (s *Server) getUserAttrValue(username, attrname string) (string, error) {
log.Debugf("getUserAttrValue user=%s, attr=%s", username, attrname)
user, err := s.registry.GetUser(username, []string{attrname})
if err != nil {
return "", err
}
attrval := user.GetAttribute(attrname)
log.Debugf("getUserAttrValue user=%s, name=%s, value=%s", username, attrname, attrval)
return attrval, nil
}

// getUserAffiliation returns a user's affiliation
func (s *Server) getUserAffiliation(username string) (string, error) {
log.Debugf("getUserAffilliation user=%s", username)
user, err := s.registry.GetUserInfo(username)
if err != nil {
return "", err
}
aff := user.Affiliation
log.Debugf("getUserAttrValue user=%s, aff=%s, value=%s", username, aff)
return aff, nil
}

func writeFile(file string, buf []byte, perm os.FileMode) error {
err := os.MkdirAll(filepath.Dir(file), 0755)
if err != nil {
Expand Down
32 changes: 16 additions & 16 deletions lib/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
"time"

"github.com/hyperledger/fabric-ca/api"
"github.com/hyperledger/fabric-ca/lib"
. "github.com/hyperledger/fabric-ca/lib"
"github.com/hyperledger/fabric-ca/lib/tls"
"github.com/hyperledger/fabric-ca/util"
)
Expand Down Expand Up @@ -59,9 +59,9 @@ func TestServerInit(t *testing.T) {

func TestRootServer(t *testing.T) {
var err error
var admin, user1 *lib.Identity
var admin, user1 *Identity
var rr *api.RegistrationResponse
var recs []lib.CertRecord
var recs []CertRecord

// Start the server
server := getRootServer(t)
Expand Down Expand Up @@ -100,7 +100,7 @@ func TestRootServer(t *testing.T) {
t.Fatalf("Failed to enroll user1: %s", err)
}
// The admin ID should have 1 cert in the DB now
recs, err = lib.MyCertDBAccessor.GetCertificatesByID("admin")
recs, err = server.CertDBAccessor().GetCertificatesByID("admin")
if err != nil {
t.Errorf("Could not get admin's certs from DB: %s", err)
}
Expand Down Expand Up @@ -186,7 +186,7 @@ func TestRunningTLSServer(t *testing.T) {
t.Errorf("Server start failed: %s", err)
}

clientConfig := &lib.ClientConfig{
clientConfig := &ClientConfig{
URL: fmt.Sprintf("https://localhost:%d", rootPort),
TLS: tls.ClientTLSConfig{
CertFilesList: []string{"../testdata/root.pem"},
Expand Down Expand Up @@ -268,11 +268,11 @@ func getRootServerURL() string {
return fmt.Sprintf("http://admin:adminpw@localhost:%d", rootPort)
}

func getRootServer(t *testing.T) *lib.Server {
func getRootServer(t *testing.T) *Server {
return getServer(rootPort, rootDir, "", 0, t)
}

func getIntermediateServer(idx int, t *testing.T) *lib.Server {
func getIntermediateServer(idx int, t *testing.T) *Server {
return getServer(
intermediatePort,
path.Join(intermediateDir, strconv.Itoa(idx)),
Expand All @@ -281,7 +281,7 @@ func getIntermediateServer(idx int, t *testing.T) *lib.Server {
t)
}

func getServer(port int, home, parentURL string, maxEnroll int, t *testing.T) *lib.Server {
func getServer(port int, home, parentURL string, maxEnroll int, t *testing.T) *Server {
if home != testdataDir {
os.RemoveAll(home)
}
Expand All @@ -293,12 +293,12 @@ func getServer(port int, home, parentURL string, maxEnroll int, t *testing.T) *l
},
"org2": nil,
}
srv := &lib.Server{
Config: &lib.ServerConfig{
srv := &Server{
Config: &ServerConfig{
Port: port,
Debug: true,
Affiliations: affiliations,
Registry: lib.ServerConfigRegistry{
Registry: ServerConfigRegistry{
MaxEnrollments: maxEnroll,
},
},
Expand All @@ -315,17 +315,17 @@ func getServer(port int, home, parentURL string, maxEnroll int, t *testing.T) *l
return srv
}

func getRootClient() *lib.Client {
func getRootClient() *Client {
return getTestClient(rootPort)
}

func getIntermediateClient() *lib.Client {
func getIntermediateClient() *Client {
return getTestClient(intermediatePort)
}

func getTestClient(port int) *lib.Client {
return &lib.Client{
Config: &lib.ClientConfig{URL: fmt.Sprintf("http://localhost:%d", port)},
func getTestClient(port int) *Client {
return &Client{
Config: &ClientConfig{URL: fmt.Sprintf("http://localhost:%d", port)},
HomeDir: testdataDir,
}
}
44 changes: 7 additions & 37 deletions lib/serverauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,46 +33,16 @@ const (
enrollmentIDHdrName = "__eid__"
)

// AuthHandler
// Fabric CA authentication handler
type fcaAuthHandler struct {
basic bool
token bool
next http.Handler
server *Server
basic bool
token bool
next http.Handler
}

var authError = cerr.NewBadRequest(errors.New("Authorization failure"))

// NewAuthWrapper is auth wrapper constructor.
// Only the "enroll" URI uses basic auth for the enrollment secret, while all
// others require a token which proves ownership of an ecert.
func NewAuthWrapper(path string, handler http.Handler, err error) (string, http.Handler, error) {
if path == "enroll" {
handler, err = newBasicAuthHandler(handler, err)
return wrappedPath(path), handler, err
}
handler, err = newTokenAuthHandler(handler, err)
return wrappedPath(path), handler, err
}

func newBasicAuthHandler(handler http.Handler, errArg error) (h http.Handler, err error) {
return newAuthHandler(true, false, handler, errArg)
}

func newTokenAuthHandler(handler http.Handler, errArg error) (h http.Handler, err error) {
return newAuthHandler(false, true, handler, errArg)
}

func newAuthHandler(basic, token bool, handler http.Handler, errArg error) (h http.Handler, err error) {
if errArg != nil {
return nil, errArg
}
ah := new(fcaAuthHandler)
ah.basic = basic
ah.token = token
ah.next = handler
return ah, nil
}

func (ah *fcaAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := ah.serveHTTP(w, r)
if err != nil {
Expand All @@ -96,7 +66,7 @@ func (ah *fcaAuthHandler) serveHTTP(w http.ResponseWriter, r *http.Request) erro
log.Debugf("Basic auth is not allowed; found %s", authHdr)
return errBasicAuthNotAllowed
}
u, err := UserRegistry.GetUser(user, nil)
u, err := ah.server.registry.GetUser(user, nil)
if err != nil {
log.Debugf("Failed to get user '%s': %s", user, err)
return authError
Expand All @@ -120,7 +90,7 @@ func (ah *fcaAuthHandler) serveHTTP(w http.ResponseWriter, r *http.Request) erro
}
r.Body = ioutil.NopCloser(bytes.NewReader(body))
// verify token
cert, err2 := util.VerifyToken(MyCSP, authHdr, body)
cert, err2 := util.VerifyToken(ah.server.csp, authHdr, body)
if err2 != nil {
log.Debugf("Failed to verify token: %s", err2)
return authError
Expand Down
Loading

0 comments on commit df922a1

Please sign in to comment.