Skip to content

Commit

Permalink
Registrar can configure max enrollment for user
Browse files Browse the repository at this point in the history
Registrar registering a user should be able to set max enrollment for
user. The max enrollment value that the registrar can set for a new
user will be less than or equal to the max enrollment value defined in
the Fabric-ca server configuration file.

Also, made some logging improvements for better readability and
debugging.

https://jira.hyperledger.org/browse/FAB-1545

Change-Id: I452d9d6c52eab31b72fa9394d9ca0ab160619501
Signed-off-by: Saad Karim <[email protected]>
Signed-off-by: Keith Smith <[email protected]>
  • Loading branch information
Saad Karim authored and Keith Smith committed Mar 5, 2017
1 parent f18b6b7 commit cd8802b
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 65 deletions.
2 changes: 0 additions & 2 deletions cmd/fabric-ca-client/enroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ func runEnroll(cmd *cobra.Command) error {
return err
}

log.Debugf("Client configuration settings: %+v", clientCfg)

cfgFile, err := ioutil.ReadFile(cfgFileName)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cmd/fabric-ca-client/revoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func runRevoke() error {
aki := viper.GetString("aki")

if enrollmentID == "" && serial == "" {
return fmt.Errorf("Invalid usage; either ENROLLMENT_ID or both --serial and --aki are required")
return fmt.Errorf("Invalid usage; either --eid or both --serial and --aki are required")
}

err = id.Revoke(
Expand Down
10 changes: 6 additions & 4 deletions lib/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,12 @@ type Client struct {
// Enroll enrolls a new identity
// @param req The enrollment request
func (c *Client) Enroll(req *api.EnrollmentRequest) (*Identity, error) {
log.Debugf("Enrolling %+v", req)
log.Debugf("Enrolling %+v", &req)

// Generate the CSR
csrPEM, key, err := c.GenCSR(req.CSR, req.Name)
if err != nil {
log.Debugf("enroll failure generating CSR: %s", err)
log.Debugf("Enroll failure generating CSR: %s", err)
return nil, err
}

Expand Down Expand Up @@ -154,7 +154,7 @@ func (c *Client) newIdentityFromResponse(result interface{}, id string, key []by

// GenCSR generates a CSR (Certificate Signing Request)
func (c *Client) GenCSR(req *api.CSRInfo, id string) ([]byte, []byte, error) {
log.Debugf("GenCSR %+v", req)
log.Debugf("GenCSR %+v", &req)

cr := c.newCertificateRequest(req)
cr.CN = id
Expand Down Expand Up @@ -215,6 +215,7 @@ func (c *Client) GetMyKeyFile() string {
if file == "" {
file = path.Join(c.GetMyEnrollmentDir(), "key.pem")
}
log.Debugf("Key file location: %s", file)
return file
}

Expand All @@ -224,6 +225,7 @@ func (c *Client) GetMyCertFile() string {
if file == "" {
file = path.Join(c.GetMyEnrollmentDir(), "cert.pem")
}
log.Debugf("Cert file location: %s", file)
return file
}

Expand Down Expand Up @@ -332,7 +334,7 @@ func (c *Client) SendPost(req *http.Request) (interface{}, error) {
}
if len(body.Errors) > 0 {
msg := body.Errors[0].Message
return nil, fmt.Errorf("Error response from server was '%s' for request:\n%s", msg, reqStr)
return nil, fmt.Errorf("Error response from server was: %s", msg)
}
}
scode := resp.StatusCode
Expand Down
82 changes: 80 additions & 2 deletions lib/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ import (

var (
tdDir = "../testdata"
fcaDB = path.Join(tdDir, "fabric-ca.db")
fcaDB = path.Join(tdDir, "fabric-ca-server.db")
fcaDB2 = path.Join(tdDir, "fabric-ca.db")
cfgFile = path.Join(tdDir, "config.json")
testCfgFile = "testconfig.json"
clientConfig = path.Join(tdDir, "client-config.json")
Expand Down Expand Up @@ -79,7 +80,7 @@ func testRegister(c *Client, t *testing.T) {

// Register as admin
registerReq := &api.RegistrationRequest{
Name: "TestUser",
Name: "TestUser2",
Type: "Client",
Affiliation: "bank_a",
}
Expand Down Expand Up @@ -209,6 +210,79 @@ func testLoadBadCSRInfo(c *Client, t *testing.T) {
}
}

func TestCustomizableMaxEnroll(t *testing.T) {
os.Remove("../testdata/fabric-ca-server.db")

srv := getServer(rootPort, testdataDir, "", 3, t)

srv.Config.Registry.MaxEnrollments = 3
srv.Config.Debug = true

err := srv.Start()
if err != nil {
t.Errorf("Server start failed: %s", err)
}

testTooManyEnrollments(t)
testIncorrectEnrollment(t)

err = srv.Stop()
if err != nil {
t.Errorf("Server stop failed: %s", err)
}
}

func testTooManyEnrollments(t *testing.T) {
clientConfig := &ClientConfig{
URL: fmt.Sprintf("http://localhost:%d", rootPort),
}

rawURL := fmt.Sprintf("http://admin:adminpw@localhost:%d", rootPort)

_, err := clientConfig.Enroll(rawURL, testdataDir)
if err != nil {
t.Errorf("Failed to enroll: %s", err)
}

_, err = clientConfig.Enroll(rawURL, testdataDir)
if err != nil {
t.Errorf("Failed to enroll: %s", err)
}

id, err := clientConfig.Enroll(rawURL, testdataDir)
if err != nil {
t.Errorf("Failed to enroll: %s", err)
}

_, err = clientConfig.Enroll(rawURL, testdataDir)
if err == nil {
t.Errorf("Enroll should have failed, no more enrollments left")
}

id.Store()
}

func testIncorrectEnrollment(t *testing.T) {
c := getTestClient(rootPort)

id, err := c.LoadMyIdentity()
if err != nil {
t.Error("Failed to load identity")
}

req := &api.RegistrationRequest{
Name: "TestUser",
Type: "Client",
Affiliation: "hyperledger",
MaxEnrollments: 4,
}

_, err = id.Register(req)
if err == nil {
t.Error("Registration should have failed, can't register user with max enrollment greater than server max enrollment setting")
}
}

func TestNormalizeUrl(t *testing.T) {
_, err := NormalizeURL("")
if err != nil {
Expand Down Expand Up @@ -256,6 +330,7 @@ func startServer() int {

if !serverStarted {
os.Remove(fcaDB)
os.Remove(fcaDB2)
os.RemoveAll(dir)
serverStarted = true
fmt.Println("starting fabric-ca server ...")
Expand All @@ -281,5 +356,8 @@ func runServer() {
func TestLast(t *testing.T) {
// Cleanup
os.Remove(fcaDB)
os.Remove(fcaDB2)
os.Remove("../testdata/cert.pem")
os.Remove("../testdata/key.pem")
os.RemoveAll(dir)
}
2 changes: 1 addition & 1 deletion lib/dbaccessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ func (u *DBUser) Login(pass string) error {
// If maxEnrollments is set to 0, user has unlimited enrollment
if u.MaxEnrollments != 0 {
if u.State >= u.MaxEnrollments {
return fmt.Errorf("The maximum number of enrollments is %d", u.MaxEnrollments)
return fmt.Errorf("No more enrollments left. The maximum number of enrollments is %d", u.MaxEnrollments)
}
}

Expand Down
6 changes: 3 additions & 3 deletions lib/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (i *Identity) Register(req *api.RegistrationRequest) (rr *api.RegistrationR
var secret string
var resp interface{}

log.Debugf("Register %+v", req)
log.Debugf("Register %+v", &req)
if req.Name == "" {
return nil, errors.New("Register was called without a Name set")
}
Expand Down Expand Up @@ -113,7 +113,7 @@ func (i *Identity) Register(req *api.RegistrationRequest) (rr *api.RegistrationR
// Reenroll reenrolls an existing Identity and returns a new Identity
// @param req The reenrollment request
func (i *Identity) Reenroll(req *api.ReenrollmentRequest) (*Identity, error) {
log.Debugf("Reenrolling %s", req)
log.Debugf("Reenrolling %s", &req)

csrPEM, key, err := i.client.GenCSR(req.CSR, i.GetName())
if err != nil {
Expand Down Expand Up @@ -142,7 +142,7 @@ func (i *Identity) Reenroll(req *api.ReenrollmentRequest) (*Identity, error) {

// Revoke the identity associated with 'id'
func (i *Identity) Revoke(req *api.RevocationRequest) error {
log.Debugf("Entering identity.Revoke %+v", req)
log.Debugf("Entering identity.Revoke %+v", &req)
reqBody, err := util.Marshal(req, "RevocationRequest")
if err != nil {
return err
Expand Down
31 changes: 18 additions & 13 deletions lib/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func (s *Server) Stop() error {

// Initialize the fabric-ca server's key material
func (s *Server) initKeyMaterial(renew bool) error {
log.Debugf("Init with home %s and config %+v", s.HomeDir, s.Config)
log.Debugf("Init with home %s and config %+v", s.HomeDir, *s.Config)

// Make the path names absolute in the config
s.makeFileNamesAbsolute()
Expand Down Expand Up @@ -269,11 +269,13 @@ func (s *Server) RegisterBootstrapUser(user, pass, affiliation string) error {
if err != nil {
return fmt.Errorf("Failed to register bootstrap user '%s': %s", user, err)
}

id := ServerConfigIdentity{
Name: user,
Pass: pass,
Type: "user",
Affiliation: affiliation,
Name: user,
Pass: pass,
Type: "user",
Affiliation: affiliation,
MaxEnrollments: s.Config.Registry.MaxEnrollments,
Attrs: map[string]string{
"hf.Registrar.Roles": "client,user,peer,validator,auditor",
"hf.Registrar.DelegateRoles": "client,user,validator,auditor",
Expand Down Expand Up @@ -334,22 +336,25 @@ func (s *Server) initConfig() (err error) {
func (s *Server) initDB() error {
db := &s.Config.DB

log.Debugf("Initializing '%s' data base at '%s'", db.Type, db.Datasource)

var err error
var exists bool

MaxEnrollments = s.Config.Registry.MaxEnrollments

if db.Type == "" {
db.Type = "sqlite3"
}
if db.Datasource == "" {
var ds string
ds, err = util.MakeFileAbs("fabric-ca-server.db", s.HomeDir)
if err != nil {
return err
}
db.Datasource = ds
db.Datasource = "fabric-ca-server.db"
}

db.Datasource, err = util.MakeFileAbs(db.Datasource, s.HomeDir)
if err != nil {
return err
}

log.Debugf("Initializing '%s' data base at '%s'", db.Type, db.Datasource)

switch db.Type {
case "sqlite3":
s.db, exists, err = dbutil.NewUserRegistrySQLLite3(db.Datasource)
Expand Down
10 changes: 7 additions & 3 deletions lib/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func TestIntermediateServer(t *testing.T) {
}
}
func TestRunningTLSServer(t *testing.T) {
srv := getServer(rootPort, testdataDir, "", t)
srv := getServer(rootPort, testdataDir, "", 0, t)

srv.Config.TLS.Enabled = true
srv.Config.TLS.CertFile = "../testdata/tls_server-cert.pem"
Expand Down Expand Up @@ -244,18 +244,19 @@ func getRootServerURL() string {
}

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

func getIntermediateServer(idx int, t *testing.T) *lib.Server {
return getServer(
intermediatePort,
path.Join(intermediateDir, strconv.Itoa(idx)),
getRootServerURL(),
0,
t)
}

func getServer(port int, home, parentURL string, t *testing.T) *lib.Server {
func getServer(port int, home, parentURL string, maxEnroll int, t *testing.T) *lib.Server {
if home != testdataDir {
os.RemoveAll(home)
}
Expand All @@ -272,6 +273,9 @@ func getServer(port int, home, parentURL string, t *testing.T) *lib.Server {
Port: port,
Debug: true,
Affiliations: affiliations,
Registry: lib.ServerConfigRegistry{
MaxEnrollments: maxEnroll,
},
},
HomeDir: home,
ParentServerURL: parentURL,
Expand Down
2 changes: 1 addition & 1 deletion lib/serverauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type fcaAuthHandler struct {
next http.Handler
}

var authError = cerr.NewBadRequest(errors.New("authorization failure"))
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
Expand Down
Loading

0 comments on commit cd8802b

Please sign in to comment.