Skip to content

Commit

Permalink
Enrollment info part of client config
Browse files Browse the repository at this point in the history
Updated the client config template to include enrollment
information. Simplified reenroll command to not require
optional CSR file, it will now be read from client config.

Enroll command will now be the only command that can be executed first.
Once client has successfully enrolled and enrollment information
exists then other client commands can be executed

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

Change-Id: I10b654c36c8c4b39b612fcb2048348074a81e9b6
Signed-off-by: Saad Karim <skarim@us.ibm.com>
  • Loading branch information
Saad Karim committed Mar 3, 2017
1 parent 4d9e2e3 commit 7c44a8f
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 33 deletions.
36 changes: 33 additions & 3 deletions cmd/fabric-ca-client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ id:
attributes:
- name:
value:
#############################################################################
# Enrollment section used to enroll a user with fabric-ca server
#############################################################################
enrollment:
hosts:
profile:
label:
`
)

Expand All @@ -136,7 +144,7 @@ var (
clientCfg *lib.ClientConfig
)

func configInit() error {
func configInit(command string) error {

var err error

Expand All @@ -152,6 +160,13 @@ func configInit() error {
}
}

if command != "enroll" {
err = checkForEnrollment()
if err != nil {
return err
}
}

// If the config file doesn't exist, create a default one
if !util.FileExists(cfgFileName) {
err = createDefaultConfigFile()
Expand Down Expand Up @@ -186,6 +201,7 @@ func configInit() error {
clientCfg.TLS.Enabled = purl.Scheme == "https"

processCertFiles(&clientCfg.TLS)

if clientCfg.ID.Attr != "" {
processAttributes()
}
Expand All @@ -203,17 +219,19 @@ func createDefaultConfigFile() error {
if err != nil {
return err
}
fabricCAServerURL = fmt.Sprintf("%s://%s", URL.Scheme, URL.Host) // URL.Scheme + "://" + URL.Host
fabricCAServerURL = fmt.Sprintf("%s://%s", URL.Scheme, URL.Host)
}

myhost := viper.GetString("myhost")

// Do string subtitution to get the default config
cfg = strings.Replace(defaultCfgTemplate, "<<<URL>>>", fabricCAServerURL, 1)
cfg = strings.Replace(cfg, "<<<MYHOST>>>", myhost, 1)
user, _, err := util.GetUser()
cfg = strings.Replace(cfg, "<<<ENROLLMENT_ID>>>", user, 1)

// Now write the file
err := os.MkdirAll(filepath.Dir(cfgFileName), 0755)
err = os.MkdirAll(filepath.Dir(cfgFileName), 0755)
if err != nil {
return err
}
Expand All @@ -223,6 +241,7 @@ func createDefaultConfigFile() error {

// processCertFiles parses comma seperated string to generate a string array
func processCertFiles(cfg *tls.ClientTLSConfig) {
log.Debug("Process comma seperated cert files")
CertFiles := strings.Split(cfg.CertFiles, ",")
cfg.CertFilesList = make([]string, 0)

Expand All @@ -237,3 +256,14 @@ func processAttributes() {
clientCfg.ID.Attributes[0].Name = splitAttr[0]
clientCfg.ID.Attributes[0].Value = strings.Join(splitAttr[1:], "")
}

func checkForEnrollment() error {
log.Debug("Checking for enrollment")

client := lib.Client{
HomeDir: filepath.Dir(cfgFileName),
Config: clientCfg,
}

return client.Enrollment()
}
21 changes: 16 additions & 5 deletions cmd/fabric-ca-client/enroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import (
"strings"

"github.com/cloudflare/cfssl/log"
"github.com/hyperledger/fabric-ca/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
Expand All @@ -42,7 +42,7 @@ var enrollCmd = &cobra.Command{
return nil
}

err := runEnroll()
err := runEnroll(cmd)
if err != nil {
return err
}
Expand All @@ -56,15 +56,26 @@ func init() {
}

// The client enroll main logic
func runEnroll() error {
func runEnroll(cmd *cobra.Command) error {
log.Debug("Entered Enroll")

rawurl := viper.GetString("url")
ID, err := clientCfg.Enroll(rawurl, filepath.Dir(cfgFileName))
_, _, err := util.GetUser()
if err != nil {
return err
}

err = configInit(cmd.Name())
if err != nil {
return err
}

ID, err := clientCfg.Enroll(clientCfg.URL, filepath.Dir(cfgFileName))
if err != nil {
return err
}

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

cfgFile, err := ioutil.ReadFile(cfgFileName)
if err != nil {
return err
Expand Down
7 changes: 0 additions & 7 deletions cmd/fabric-ca-client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,8 @@ var rootCmd = &cobra.Command{
Use: cmdName,
Short: longName,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
err := configInit()
if err != nil {
return err
}

util.CmdRunBegin()

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

return nil
},
}
Expand Down
29 changes: 17 additions & 12 deletions cmd/fabric-ca-client/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ func TestCreateDefaultConfigFile(t *testing.T) {
defYaml = util.GetDefaultConfigFile("fabric-ca-client")
os.Remove(defYaml)

fabricCAServerURL := "http://localhost:7058"
enrollURL := "http://admin:admin2@localhost:7058"

err := RunMain([]string{cmdName, "enroll", "-u", fabricCAServerURL, "-m", myhost})
err := RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-m", myhost})
if err == nil {
t.Errorf("No username/password provided, should have errored")
}
Expand All @@ -70,7 +70,7 @@ func TestCreateDefaultConfigFile(t *testing.T) {

configFile := string(fileBytes)

if !strings.Contains(configFile, fabricCAServerURL) {
if !strings.Contains(configFile, "localhost:7058") {
t.Error("Failed to update default config file with url")
}

Expand Down Expand Up @@ -110,7 +110,6 @@ func TestClientCommandsNoTLS(t *testing.T) {
}

testEnroll(t)
testReenroll(t)
testRegisterConfigFile(t)
testRegisterEnvVar(t)
testRegisterCommandLine(t)
Expand Down Expand Up @@ -149,7 +148,7 @@ func testEnroll(t *testing.T) {
t.Log("Testing Enroll CMD")
defYaml = util.GetDefaultConfigFile("fabric-ca-client")

os.RemoveAll(defYaml) // Clean up any left over config file
os.Remove(defYaml) // Clean up any left over config file

// Negative test case, enroll command without username/password
err := RunMain([]string{cmdName, "enroll", "-d"})
Expand All @@ -162,7 +161,7 @@ func testEnroll(t *testing.T) {
t.Errorf("client enroll -u failed: %s", err)
}

os.Remove(defYaml)
testReenroll(t)

err = RunMain([]string{cmdName, "enroll", "-u", "http://admin2:adminpw2@localhost:7055"})
if err == nil {
Expand All @@ -177,7 +176,7 @@ func testReenroll(t *testing.T) {
t.Log("Testing Reenroll CMD")
defYaml = util.GetDefaultConfigFile("fabric-ca-client")

err := RunMain([]string{cmdName, "reenroll", "-u", "http://localhost:7054"})
err := RunMain([]string{cmdName, "reenroll", "-u", "http://localhost:7054", "--enrollment.hosts", "host1,host2"})
if err != nil {
t.Errorf("client reenroll --url -f failed: %s", err)
}
Expand Down Expand Up @@ -342,7 +341,7 @@ func TestClientCommandsTLSEnvVar(t *testing.T) {
os.Setenv(clientKeyEnvVar, tlsClientKeyFile)
os.Setenv(clientCertEnvVar, tlsClientCertFile)

err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "-u", "https://admin:adminpw@localhost:7054", "-d"})
err = RunMain([]string{cmdName, "enroll", "-d", "-c", testYaml, "-u", "https://admin:adminpw@localhost:7054", "-d"})
if err != nil {
t.Errorf("client enroll -c -u failed: %s", err)
}
Expand All @@ -355,7 +354,6 @@ func TestClientCommandsTLSEnvVar(t *testing.T) {
os.Unsetenv(rootCertEnvVar)
os.Unsetenv(clientKeyEnvVar)
os.Unsetenv(clientCertEnvVar)

}

func TestClientCommandsTLS(t *testing.T) {
Expand All @@ -376,15 +374,15 @@ func TestClientCommandsTLS(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)
}

err = RunMain([]string{cmdName, "enroll", "-c", "../../testdata/test.yaml", "--tls.certfiles", "root.pem", "--tls.client.keyfile", "tls_client-key.pem", "--tls.client.certfile", "tls_client-cert.pem", "-u", "https://admin:adminpw@localhost:7054", "-d"})
err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "--tls.certfiles", rootCert, "--tls.client.keyfile", tlsClientKeyFile, "--tls.client.certfile", tlsClientCertFile, "-u", "https://admin:adminpw@localhost:7054", "-d"})
if err != nil {
t.Errorf("client enroll -c -u failed: %s", err)
}
Expand All @@ -401,3 +399,10 @@ func TestCleanUp(t *testing.T) {
os.Remove(testYaml)
os.Remove(fabricCADB)
}

func TestRegisterWithoutEnroll(t *testing.T) {
err := RunMain([]string{cmdName, "register", "-c", testYaml})
if err == nil {
t.Errorf("Should have failed, as no enrollment information should exist. Enroll commands needs to be the first command to be executed")
}
}
20 changes: 16 additions & 4 deletions cmd/fabric-ca-client/reenroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ var reenrollCmd = &cobra.Command{
Use: "reenroll",
Short: "Reenroll user",
Long: "Reenroll user with fabric-ca server",
PreRunE: func(cmd *cobra.Command, args []string) error {
err := configInit(cmd.Name())
if err != nil {
return err
}

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

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
cmd.Help()
Expand All @@ -48,9 +58,6 @@ var reenrollCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(reenrollCmd)
reenrollFlags := reenrollCmd.Flags()
reenrollFlags.StringVarP(&csrFile, "csrfile", "f", "", "Certificate Signing Request information (Optional)")

}

// The client reenroll main logic
Expand All @@ -67,7 +74,12 @@ func runReenroll() error {
return err
}

req := &api.ReenrollmentRequest{}
req := &api.ReenrollmentRequest{
Hosts: clientCfg.Enrollment.Hosts,
Label: clientCfg.Enrollment.Label,
Profile: clientCfg.Enrollment.Profile,
CSR: &clientCfg.CSR,
}

newID, err := id.Reenroll(req)
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions cmd/fabric-ca-client/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ var registerCmd = &cobra.Command{
Use: "register",
Short: "Register user",
Long: "Register user with fabric-ca server",
PreRunE: func(cmd *cobra.Command, args []string) error {
err := configInit(cmd.Name())
if err != nil {
return err
}

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

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
cmd.Help()
Expand Down
10 changes: 10 additions & 0 deletions cmd/fabric-ca-client/revoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ var revokeCmd = &cobra.Command{
Use: "revoke",
Short: "Revoke user",
Long: "Revoke user with fabric-ca server",
PreRunE: func(cmd *cobra.Command, args []string) error {
err := configInit(cmd.Name())
if err != nil {
return err
}

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

return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
cmd.Help()
Expand Down
9 changes: 9 additions & 0 deletions lib/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
Expand Down Expand Up @@ -357,6 +358,14 @@ func (c *Client) getURL(endpoint string) (string, error) {
return rtn, nil
}

// Enrollment checks to see if client is enrolled (i.e. enrollment information exists)
func (c *Client) Enrollment() error {
if !util.FileExists(c.GetMyCertFile()) || !util.FileExists(c.GetMyKeyFile()) {
return errors.New("Enrollment information does not exist. Please execute enroll command first. Example: fabric-ca-client enroll -u http://user:userpw@serverAddr:serverPort")
}
return nil
}

func (c *Client) getClientConfig(path string) ([]byte, error) {
log.Debug("Retrieving client config")
// fcaClient := filepath.Join(path, clientConfigFile)
Expand Down
4 changes: 2 additions & 2 deletions lib/clientconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package lib
import (
"net/url"

"github.com/cloudflare/cfssl/csr"
"github.com/hyperledger/fabric-ca/api"
"github.com/hyperledger/fabric-ca/lib/tls"
)
Expand All @@ -30,7 +29,7 @@ type ClientConfig struct {
URL string `def:"http://localhost:7054" opt:"u" help:"URL of fabric-ca-server"`
TLS tls.ClientTLSConfig
Enrollment api.EnrollmentRequest
CSR csr.CertificateRequest
CSR api.CSRInfo
ID api.RegistrationRequest
}

Expand All @@ -51,6 +50,7 @@ func (c *ClientConfig) Enroll(rawurl, home string) (id *Identity, err error) {
}
c.URL = purl.String()
c.TLS.Enabled = purl.Scheme == "https"
c.Enrollment.CSR = &c.CSR
client := &Client{HomeDir: home, Config: c}
return client.Enroll(&c.Enrollment)
}
2 changes: 2 additions & 0 deletions lib/serverenroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ func (sh *signHandler) Handle(w http.ResponseWriter, r *http.Request) error {
return err
}

log.Debugf("Enrollment request: %+v\n", req)

// Make any authorization checks needed, depending on the contents
// of the CSR (Certificate Signing Request)
err = csrAuthCheck(&req, r)
Expand Down

0 comments on commit 7c44a8f

Please sign in to comment.