From 4d9e2e360394f811c98fc61055f3f9967d372d25 Mon Sep 17 00:00:00 2001 From: Saad Karim Date: Tue, 14 Feb 2017 13:03:15 -0500 Subject: [PATCH] Registration request part of client config Registration process simplified by incorporate registration information in the overall client config file. This eliminates having to provide a register file through a flag in the register CLI. Registrar will update this config file with any relevant user information before calling the register request from the command line. This will be followed up with another change-set that will force the client to only be able to execute enroll command as it first command. This will create the enrollment data, client config file, and client home directory. This is all pertinent information that is needed for other commands to complete successfully. https://jira.hyperledger.org/browse/FAB-2233 Change-Id: I61bdabe75a7d14425864e9eed2be6dc771f8d31e Signed-off-by: Saad Karim --- .gitignore | 1 + api/client.go | 12 +-- cmd/fabric-ca-client/config.go | 26 +++++- cmd/fabric-ca-client/main_test.go | 110 ++++++++++++++++---------- cmd/fabric-ca-client/register.go | 29 +------ lib/clientconfig.go | 1 + lib/server_test.go | 2 + lib/serverregister.go | 2 +- testdata/fabric-ca-client-config.yaml | 17 +++- 9 files changed, 123 insertions(+), 77 deletions(-) diff --git a/.gitignore b/.gitignore index a552516d7..42f1b44a4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ testdata/fabric*ca.db testdata/initFabricCaFvt.json testdata/openssl.cnf.base.this testdata/runFabricCaFvt.json +fabric-ca diff --git a/api/client.go b/api/client.go index 7b29065a2..f547e5c3e 100644 --- a/api/client.go +++ b/api/client.go @@ -26,19 +26,21 @@ import ( // RegistrationRequest for a new identity type RegistrationRequest struct { // Name is the unique name of the identity - Name string `json:"id"` + Name string `json:"id" help:"Unique name of the identity"` // Type of identity being registered (e.g. "peer, app, user") - Type string `json:"type"` + Type string `json:"type" help:"Type of identity being registered (e.g. 'peer, app, user')"` // Secret is an optional password. If not specified, // a random secret is generated. In both cases, the secret // is returned in the RegistrationResponse. - Secret string `json:"secret,omitempty"` + Secret string `json:"secret,omitempty" help:"The enrollment secret for the identity being registered"` // MaxEnrollments is the maximum number of times the secret can // be reused to enroll. - MaxEnrollments int `json:"max_enrollments,omitempty"` + MaxEnrollments int `json:"max_enrollments,omitempty" help:"The maximum number of times the secret can be reused to enroll."` // is returned in the response. // Group name associated with the identity - Group string `json:"group"` + Group string `json:"group" help:"Name associated with the identity"` + // Attr is used to support a single attribute provided through the fabric-ca-client CLI + Attr string `help:"Attributes associated with this identity (e.g. hf.Revoker=true)"` // Attributes associated with this identity Attributes []Attribute `json:"attrs,omitempty"` } diff --git a/cmd/fabric-ca-client/config.go b/cmd/fabric-ca-client/config.go index b76c0d6ef..e241f1234 100644 --- a/cmd/fabric-ca-client/config.go +++ b/cmd/fabric-ca-client/config.go @@ -53,10 +53,14 @@ const ( # Examples: # a) --url https://localhost:7054 # To set the fabric-ca server url +# b) --tls.client.certfile certfile.pem +# To set the client certificate for TLS # 2) environment variable # Examples: # a) FABRIC_CA_CLIENT_URL=https://localhost:7054 # To set the fabric-ca server url +# b) FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE=certfile.pem +# To set the client certificate for TLS # 3) configuration file # 4) default value (if there is one) # All default values are shown beside each element below. @@ -110,6 +114,17 @@ csr: pathlen: pathlenzero: expiry: + +############################################################################# +# Registration section used to register a new user with fabric-ca server +############################################################################# +id: + name: + type: + group: + attributes: + - name: + value: ` ) @@ -171,7 +186,9 @@ func configInit() error { clientCfg.TLS.Enabled = purl.Scheme == "https" processCertFiles(&clientCfg.TLS) - + if clientCfg.ID.Attr != "" { + processAttributes() + } return nil } @@ -213,3 +230,10 @@ func processCertFiles(cfg *tls.ClientTLSConfig) { cfg.CertFilesList = append(cfg.CertFilesList, strings.TrimSpace(CertFiles[i])) } } + +// processAttributes parses attributes from command line +func processAttributes() { + splitAttr := strings.Split(clientCfg.ID.Attr, "=") + clientCfg.ID.Attributes[0].Name = splitAttr[0] + clientCfg.ID.Attributes[0].Value = strings.Join(splitAttr[1:], "") +} diff --git a/cmd/fabric-ca-client/main_test.go b/cmd/fabric-ca-client/main_test.go index 3d2ccbc9d..28c2e9f1a 100644 --- a/cmd/fabric-ca-client/main_test.go +++ b/cmd/fabric-ca-client/main_test.go @@ -30,18 +30,25 @@ import ( ) const ( - testYaml = "test.yaml" - myhost = "hostname" - certfile = "ec.pem" - keyfile = "ec-key.pem" - tdDir = "../../testdata" - db = "fabric-ca-server.db" + testYaml = "../../testdata/test.yaml" + myhost = "hostname" + certfile = "ec.pem" + keyfile = "ec-key.pem" + tlsCertFile = "tls_server-cert.pem" + tlsKeyFile = "tls_server-key.pem" + rootCert = "root.pem" + tlsClientCertFile = "tls_client-cert.pem" + tlsClientKeyFile = "tls_client-key.pem" + tdDir = "../../testdata" + db = "fabric-ca-server.db" + rootCertEnvVar = "FABRIC_CA_CLIENT_TLS_CERTFILES" + clientKeyEnvVar = "FABRIC_CA_CLIENT_TLS_CLIENT_KEYFILE" + clientCertEnvVar = "FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE" ) var ( defYaml string fabricCADB = path.Join(tdDir, db) - rrFile = path.Join(tdDir, "registerrequest.json") ) // TestCreateDefaultConfigFile test to make sure default config file gets generated correctly @@ -80,6 +87,7 @@ func TestClientCommandsNoTLS(t *testing.T) { srv := getServer() srv.HomeDir = tdDir + srv.Config.Debug = true err := srv.RegisterBootstrapUser("admin", "adminpw", "bank1") if err != nil { @@ -103,7 +111,9 @@ func TestClientCommandsNoTLS(t *testing.T) { testEnroll(t) testReenroll(t) - testRegister(t) + testRegisterConfigFile(t) + testRegisterEnvVar(t) + testRegisterCommandLine(t) testRevoke(t) testBogus(t) @@ -152,11 +162,6 @@ func testEnroll(t *testing.T) { t.Errorf("client enroll -u failed: %s", err) } - err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "-u", "http://admin2:adminpw2@localhost:7054"}) - if err != nil { - t.Errorf("client enroll -c -u failed: %s", err) - } - os.Remove(defYaml) err = RunMain([]string{cmdName, "enroll", "-u", "http://admin2:adminpw2@localhost:7055"}) @@ -165,7 +170,6 @@ func testEnroll(t *testing.T) { } os.Remove(defYaml) - os.Remove(testYaml) } // TestReenroll tests fabric-ca-client reenroll @@ -178,39 +182,66 @@ func testReenroll(t *testing.T) { t.Errorf("client reenroll --url -f failed: %s", err) } - err = RunMain([]string{cmdName, "reenroll", "-c", testYaml}) + os.Remove(defYaml) +} + +// testRegisterConfigFile tests fabric-ca-client register using the config file +func testRegisterConfigFile(t *testing.T) { + t.Log("Testing Register CMD") + defYaml = util.GetDefaultConfigFile("fabric-ca-client") + + err := RunMain([]string{cmdName, "enroll", "-d", "-c", "../../testdata/fabric-ca-client-config.yaml", "-u", "http://admin2:adminpw2@localhost:7054"}) + if err != nil { + t.Errorf("client enroll -u failed: %s", err) + } + + err = RunMain([]string{cmdName, "register", "-d", "-c", "../../testdata/fabric-ca-client-config.yaml"}) if err != nil { - t.Errorf("client reenroll -c failed: %s", err) + t.Errorf("client register failed using config file: %s", err) } os.Remove(defYaml) - os.Remove(testYaml) } -// TestRegister tests fabric-ca-client register -func testRegister(t *testing.T) { +// testRegisterEnvVar tests fabric-ca-client register using environment variables +func testRegisterEnvVar(t *testing.T) { t.Log("Testing Register CMD") defYaml = util.GetDefaultConfigFile("fabric-ca-client") - err := RunMain([]string{cmdName, "register", "-c", testYaml}) - if err == nil { - t.Error("Should have failed, no register request file provided") + os.Setenv("FABRIC_CA_CLIENT_ID_NAME", "testRegister2") + os.Setenv("FABRIC_CA_CLIENT_ID_GROUP", "bank_a") + os.Setenv("FABRIC_CA_CLIENT_ID_TYPE", "client") + + err := RunMain([]string{cmdName, "register"}) + if err != nil { + t.Errorf("client register failed using environment variables: %s", err) } - err = RunMain([]string{cmdName, "register", "-f", rrFile}) + os.Unsetenv("FABRIC_CA_CLIENT_ID_NAME") + os.Unsetenv("FABRIC_CA_CLIENT_TLS_ID_GROUP") + os.Unsetenv("FABRIC_CA_CLIENT_TLS_ID_TYPE") + + os.Remove(defYaml) +} + +// testRegisterCommandLine tests fabric-ca-client register using command line input +func testRegisterCommandLine(t *testing.T) { + t.Log("Testing Register CMD") + defYaml = util.GetDefaultConfigFile("fabric-ca-client") + + err := RunMain([]string{cmdName, "register", "-d", "--id.name", "testRegister3", "--id.group", "bank_a", "--id.type", "client", "--id.attr", "hf.test=a=b"}) if err != nil { - t.Errorf("client register -f failed: %s", err) + t.Errorf("client register failed: %s", err) } os.Remove(defYaml) // Delete default config file - err = RunMain([]string{cmdName, "register", "--url", "http://localhost:7055", "-f", rrFile}) + err = RunMain([]string{cmdName, "register", "-u", "http://localhost:7055"}) if err == nil { t.Error("Should have failed, client config file should have incorrect port (7055) for server") } os.Remove(defYaml) - os.Remove(testYaml) } // TestRevoke tests fabric-ca-client revoke @@ -239,7 +270,6 @@ func testRevoke(t *testing.T) { } os.RemoveAll(filepath.Dir(defYaml)) - os.Remove(testYaml) } // TestBogus tests a negative test case @@ -263,8 +293,8 @@ func TestClientCommandsUsingConfigFile(t *testing.T) { srv.HomeDir = tdDir srv.Config.TLS.Enabled = true - srv.Config.TLS.CertFile = "tls_server-cert.pem" - srv.Config.TLS.KeyFile = "tls_server-key.pem" + srv.Config.TLS.CertFile = tlsCertFile + srv.Config.TLS.KeyFile = tlsKeyFile err = srv.Start() if err != nil { @@ -300,19 +330,19 @@ func TestClientCommandsTLSEnvVar(t *testing.T) { srv.HomeDir = tdDir srv.Config.TLS.Enabled = true - srv.Config.TLS.CertFile = "tls_server-cert.pem" - srv.Config.TLS.KeyFile = "tls_server-key.pem" + srv.Config.TLS.CertFile = tlsCertFile + srv.Config.TLS.KeyFile = tlsKeyFile err = srv.Start() if err != nil { t.Errorf("Server start failed: %s", err) } - os.Setenv("FABRIC_CA_CLIENT_TLS_CERTFILES", "root.pem") - os.Setenv("FABRIC_CA_CLIENT_TLS_CLIENT_KEYFILE", "tls_client-key.pem") - os.Setenv("FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE", "tls_client-cert.pem") + os.Setenv(rootCertEnvVar, rootCert) + os.Setenv(clientKeyEnvVar, tlsClientKeyFile) + os.Setenv(clientCertEnvVar, tlsClientCertFile) - err = RunMain([]string{cmdName, "enroll", "-c", "../../testdata/test.yaml", "-u", "https://admin:adminpw@localhost:7054", "-d"}) + err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "-u", "https://admin:adminpw@localhost:7054", "-d"}) if err != nil { t.Errorf("client enroll -c -u failed: %s", err) } @@ -322,9 +352,9 @@ func TestClientCommandsTLSEnvVar(t *testing.T) { t.Errorf("Server stop failed: %s", err) } - os.Unsetenv("FABRIC_CA_CLIENT_TLS_CERTFILES") - os.Unsetenv("FABRIC_CA_CLIENT_TLS_CLIENT_KEYFILE") - os.Unsetenv("FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE") + os.Unsetenv(rootCertEnvVar) + os.Unsetenv(clientKeyEnvVar) + os.Unsetenv(clientCertEnvVar) } @@ -366,10 +396,8 @@ func TestClientCommandsTLS(t *testing.T) { } func TestCleanUp(t *testing.T) { - os.Remove("cert.pem") - os.Remove("key.pem") os.Remove("../../testdata/cert.pem") os.Remove("../../testdata/key.pem") - os.Remove("../../testdata/test.yaml") + os.Remove(testYaml) os.Remove(fabricCADB) } diff --git a/cmd/fabric-ca-client/register.go b/cmd/fabric-ca-client/register.go index 2c249b52c..0c49003f4 100644 --- a/cmd/fabric-ca-client/register.go +++ b/cmd/fabric-ca-client/register.go @@ -17,17 +17,12 @@ limitations under the License. package main import ( - "encoding/json" - "errors" "fmt" "path/filepath" "github.com/cloudflare/cfssl/log" - "github.com/hyperledger/fabric-ca/api" "github.com/hyperledger/fabric-ca/lib" - "github.com/hyperledger/fabric-ca/util" "github.com/spf13/cobra" - "github.com/spf13/viper" ) // initCmd represents the init command @@ -52,32 +47,12 @@ var registerCmd = &cobra.Command{ func init() { rootCmd.AddCommand(registerCmd) - registerFlags := registerCmd.Flags() - util.FlagString(registerFlags, "regfile", "f", "", "File containing registration info") } // The client register main logic func runRegister() error { log.Debug("Entered Register") - regFile := viper.GetString("regfile") - if regFile == "" { - return errors.New("A registeration request file is required to register a user") - } - - log.Debugf("Registeration Request File: %s", regFile) - - buf, err := util.ReadFile(regFile) - if err != nil { - return err - } - - regReq := new(api.RegistrationRequest) - err = json.Unmarshal(buf, regReq) - if err != nil { - return fmt.Errorf("Failure json unmarshaling file '%s': %s", regFile, err) - } - client := lib.Client{ HomeDir: filepath.Dir(cfgFileName), Config: clientCfg, @@ -88,12 +63,12 @@ func runRegister() error { return err } - resp, err := id.Register(regReq) + resp, err := id.Register(&clientCfg.ID) if err != nil { return err } - fmt.Printf("One time password: %s\n", resp.Secret) + fmt.Printf("Password: %s\n", resp.Secret) return nil } diff --git a/lib/clientconfig.go b/lib/clientconfig.go index 1f3f65b66..a48d5ded8 100644 --- a/lib/clientconfig.go +++ b/lib/clientconfig.go @@ -31,6 +31,7 @@ type ClientConfig struct { TLS tls.ClientTLSConfig Enrollment api.EnrollmentRequest CSR csr.CertificateRequest + ID api.RegistrationRequest } // Enroll a client given the server's URL and the client's home directory. diff --git a/lib/server_test.go b/lib/server_test.go index 9d0da2ec5..0aa6df294 100644 --- a/lib/server_test.go +++ b/lib/server_test.go @@ -203,6 +203,8 @@ func TestRunningTLSServer(t *testing.T) { t.Errorf("Failed to enroll over TLS: %s", err) } + time.Sleep(1 * time.Second) + err = srv.Stop() if err != nil { t.Errorf("Server stop failed: %s", err) diff --git a/lib/serverregister.go b/lib/serverregister.go index f27410165..f664c3a28 100644 --- a/lib/serverregister.go +++ b/lib/serverregister.go @@ -76,7 +76,7 @@ func (h *registerHandler) Handle(w http.ResponseWriter, r *http.Request) error { // RegisterUser will register a user func (h *registerHandler) RegisterUser(id string, userType string, group string, attributes []api.Attribute, registrar string, opt ...string) (string, error) { - log.Debugf("Received request to register user with id: %s, group: %s, attributes: %s, registrar: %s\n", + log.Debugf("Received request to register user with id: %s, group: %s, attributes: %+v, registrar: %s\n", id, group, attributes, registrar) var tok string diff --git a/testdata/fabric-ca-client-config.yaml b/testdata/fabric-ca-client-config.yaml index a953ba256..7e9f7e3d2 100644 --- a/testdata/fabric-ca-client-config.yaml +++ b/testdata/fabric-ca-client-config.yaml @@ -55,7 +55,7 @@ tls: # an enrollment certificate (ECert) ############################################################################# csr: - cn: admin + cn: admin2 names: - C: US ST: "North Carolina" @@ -63,8 +63,21 @@ csr: O: Hyperledger OU: Fabric hosts: - - saads-mbp.raleigh.ibm.com + - hostname ca: pathlen: pathlenzero: expiry: + +############################################################################# +# Registration section used to register a new user with fabric-ca server +############################################################################# +id: + name: testRegister + type: user + group: bank_a + attributes: + - name: hf.Revoker + value: true + - name: hf.foo + value: bar