Skip to content

Commit

Permalink
fabric-ca-client commands for cobra/viper CLI
Browse files Browse the repository at this point in the history
This change set is a continuation of the rebase of fabric-ca CLI
on cobra/viper.  This change set implements fabric-ca-client commands.

Default behavior changed to use http when connecting to server. Test
cases will be added for TLS through new command line in a future
change set using new server start and stop feature introduced as part
of the new fabric-ca server CLI.

See https://jira.hyperledger.org/browse/FAB-2012

Change-Id: I669ec58287447705e7cbf938c198db4d82135ca6
Signed-off-by: Saad Karim <skarim@us.ibm.com>
Signed-off-by: Keith Smith <bksmith@us.ibm.com>
  • Loading branch information
Saad Karim authored and Keith Smith committed Feb 18, 2017
1 parent 5079a30 commit 37b897b
Show file tree
Hide file tree
Showing 29 changed files with 450 additions and 1,215 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ DOCKER_ORG = hyperledger
IMAGES = $(PROJECT_NAME) $(PROJECT_NAME)-fvt

path-map.fabric-ca := ./
path.map.fabric-ca-client := ./cmd/fabric-ca-client
path.map.fabric-ca-server := ./cmd/fabric-ca-server
path-map.fabric-ca-client := ./cmd/fabric-ca-client
path-map.fabric-ca-server := ./cmd/fabric-ca-server

include docker-env.mk

Expand Down
3 changes: 2 additions & 1 deletion cli/client/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package client

import (
"path"
"path/filepath"

"github.com/hyperledger/fabric-ca/lib"

Expand All @@ -28,7 +29,7 @@ import (
// LoadClient loads client configuration file
func loadClient(loadIdentity bool, configFile string) (*lib.Client, *lib.Identity, error) {
if configFile == "" {
configFile = path.Join(util.GetDefaultHomeDir(), "client-config.json")
configFile = path.Join(filepath.Dir(util.GetDefaultConfigFile("fabric-ca-client")), "client-config.json")
}
log.Infof("Fabric-ca Client Configuration File: %s", configFile)

Expand Down
3 changes: 2 additions & 1 deletion cli/server/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/json"
"io/ioutil"
"path"
"path/filepath"

"github.com/cloudflare/cfssl/cli"
"github.com/cloudflare/cfssl/csr"
Expand Down Expand Up @@ -74,7 +75,7 @@ func initMain(args []string, c cli.Config) (err error) {
return err
}

FCAHome, err := util.CreateHome()
FCAHome := filepath.Dir(util.GetDefaultConfigFile("fabric-ca-server"))
if err != nil {
return err
}
Expand Down
17 changes: 7 additions & 10 deletions cli/server/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,15 @@ import (
"errors"
"io/ioutil"
"os"
"path"
"testing"

"github.com/cloudflare/cfssl/cli"
"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/initca"
"github.com/cloudflare/cfssl/log"
"github.com/hyperledger/fabric-ca/util"
)

func TestInitCA(t *testing.T) {
FCAHome, err := util.CreateHome()
if err != nil {
log.Fatalf("Failed to create fabric-ca home directory.")
}

req := csr.CertificateRequest{
KeyRequest: csr.NewBasicKeyRequest(),
}
Expand Down Expand Up @@ -65,19 +58,18 @@ func TestInitCA(t *testing.T) {
}

cli.PrintCert(key, csrPEM, cert)
certerr := ioutil.WriteFile(path.Join(FCAHome, "server-cert.pem"), cert, 0755)
certerr := ioutil.WriteFile("server-cert.pem", cert, 0755)
if certerr != nil {
log.Fatal("Error writing server-cert.pem to CA_CFG_PATH directory")
}
keyerr := ioutil.WriteFile(path.Join(FCAHome, "server-key.pem"), key, 0755)
keyerr := ioutil.WriteFile("server-key.pem", key, 0755)
if keyerr != nil {
log.Fatal("Error writing server-key.pem to CA_CFG_PATH directory")
}
} else {
var ca *csr.CAConfig
req.CA = ca
if req.CA != nil {
err = errors.New("ca section only permitted in initca")
return
}

Expand Down Expand Up @@ -142,3 +134,8 @@ func TestInitCommand(t *testing.T) {
Command()
os.Args = osArgs
}

func TestCleanUp(t *testing.T) {
os.Remove("server-cert.pem")
os.Remove("server-key.pem")
}
5 changes: 0 additions & 5 deletions cli/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,6 @@ func startMain(args []string, c cli.Config) error {
log.Debug("server.startMain")
var err error

homeDir, err = util.CreateHome()
if err != nil {
return err
}

configInit(&c)

if c.CAFile == "" || c.CAKeyFile == "" {
Expand Down
104 changes: 51 additions & 53 deletions cmd/fabric-ca-client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ package main
import (
"fmt"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
"strings"

"github.com/cloudflare/cfssl/log"
"github.com/hyperledger/fabric-ca/lib"
"github.com/hyperledger/fabric-ca/util"
"github.com/spf13/viper"
)
Expand Down Expand Up @@ -81,43 +82,52 @@ serverURL: <<<URL>>>
# TLS section for the client's listenting port
#############################################################################
tls:
# Enable TLS (default: false)
enabled: false
# Enable TLS (default: false)
enabled: false
# TLS for the client's listenting port (default: false)
certfiles:
client:
certfile:
keyfile:
# TLS for the client's listenting port (default: false)
caFile:
certFile:
keyFile:
#############################################################################
# Certificate Signing Request section for generating the CSR for
# an enrollment certificate (ECert)
#############################################################################
csr:
cn: <<<ENROLLMENT_ID>>>
names:
- C: US
ST: "North Carolina"
L:
O: Hyperledger
OU: Fabric
hosts:
- <<<MYHOST>>>
ca:
pathlen:
pathlenzero:
expiry:
cn: <<<ENROLLMENT_ID>>>
names:
- C: US
ST: "North Carolina"
L:
O: Hyperledger
OU: Fabric
hosts:
- <<<MYHOST>>>
ca:
pathlen:
pathlenzero:
expiry:
`
)

var (
// cfgFileName is the name of the client's config file
cfgFileName string

// clientCfg is the client's config
clientCfg *lib.ClientConfig
)

func configInit() error {

var err error

if cfgFileName != "" {
log.Infof("User provided config file: %s\n", cfgFileName)
}

// Make the config file name absolute
if !filepath.IsAbs(cfgFileName) {
cfgFileName, err = filepath.Abs(cfgFileName)
Expand All @@ -139,57 +149,45 @@ func configInit() error {

// Call viper to read the config
viper.SetConfigFile(cfgFileName)
viper.SetConfigType("yaml")
viper.AutomaticEnv() // read in environment variables that match
err = viper.ReadInConfig()
if err != nil {
return fmt.Errorf("Failed to read config file: %s", err)
}

return nil

}

// Get the default path for the config file to display in usage message
func getDefaultConfigFile() string {
var fname = fmt.Sprintf("%s-config.yaml", cmdName)
// First check home env variables
home := "."
envs := []string{"FABRIC_CA_CLIENT_HOME", "CA_CFG_PATH", "HOME"}
for _, env := range envs {
envVal := os.Getenv(env)
if envVal != "" {
home = envVal
break
}
// Unmarshal the config into 'clientCfg'
clientCfg = new(lib.ClientConfig)
err = viper.Unmarshal(clientCfg)
if err != nil {
util.Fatal("Failed to unmarshall client config: %s", err)
}
return path.Join(home, ".fabric-ca-client", fname)

return nil
}

func createDefaultConfigFile() error {
var err error
// Create a default config, if URL provided via CLI or envar update config files
url := viper.GetString("url")
if url == "" {
url = util.GetServerURL()
}

enrollID := viper.GetString("enrollid")

host := viper.GetString("host")
if host == "" {
host, err = os.Hostname()
var cfg string
fabricCAServerURL := viper.GetString("url")
if fabricCAServerURL == "" {
fabricCAServerURL = util.GetServerURL()
} else {
URL, err := url.Parse(fabricCAServerURL)
if err != nil {
log.Error(err)
return err
}
fabricCAServerURL = fmt.Sprintf("%s://%s", URL.Scheme, URL.Host) // URL.Scheme + "://" + URL.Host
}

myhost := viper.GetString("myhost")

// Do string subtitution to get the default config
cfg := strings.Replace(defaultCfgTemplate, "<<<URL>>>", url, 1)
cfg = strings.Replace(defaultCfgTemplate, "<<<ENROLLMENT_ID>>>", enrollID, 1)
cfg = strings.Replace(defaultCfgTemplate, "<<<MYHOST>>>", host, 1)
cfg = strings.Replace(defaultCfgTemplate, "<<<URL>>>", fabricCAServerURL, 1)
cfg = strings.Replace(cfg, "<<<MYHOST>>>", myhost, 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 Down
26 changes: 21 additions & 5 deletions cmd/fabric-ca-client/enroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ limitations under the License.
package main

import (
"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"
)
Expand All @@ -29,7 +33,7 @@ var (

// initCmd represents the init command
var enrollCmd = &cobra.Command{
Use: "enroll",
Use: "enroll -u http://user:userpw@serverAddr:serverPort",
Short: "Enroll user",
Long: "Enroll user with fabric-ca server",
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -49,8 +53,6 @@ var enrollCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(enrollCmd)
enrollFlags := enrollCmd.Flags()
util.FlagString(enrollFlags, "user", "u", "", "user:pass for user being enrolled")
}

// The client enroll main logic
Expand All @@ -67,9 +69,23 @@ func runEnroll() error {
Secret: pass,
}

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

ID, err := client.Enroll(req)
if err != nil {
return err
}

err = ID.Store()
if err != nil {
return fmt.Errorf("Failed to store enrollment information: %s", err)
}

log.Infof("User Enrolled")
log.Infof("Enrollment information was successfully stored in %s and %s",
client.GetMyKeyFile(), client.GetMyCertFile())

return nil
}
8 changes: 4 additions & 4 deletions cmd/fabric-ca-client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var (

func init() {
// Get the default config file path
cfg := getDefaultConfigFile()
cfg := util.GetDefaultConfigFile(cmdName)

// All env variables must be prefixed
viper.SetEnvPrefix(envVarPrefix)
Expand All @@ -64,9 +64,9 @@ func init() {
// Set global flags used by all commands
pflags := rootCmd.PersistentFlags()
pflags.StringVarP(&cfgFileName, "config", "c", cfg, "Configuration file")
util.FlagString(pflags, "url", "", url, "URL of the Fabric-ca server")
util.FlagString(pflags, "host", "", host, "Hostname")
util.FlagString(pflags, "enrollid", "e", "", "Enrollment ID")
util.FlagString(pflags, "url", "u", url, "URL of the Fabric-ca server")
util.FlagString(pflags, "myhost", "m", host,
"Hostname to include in the certificate signing request during enrollment")
util.FlagBool(pflags, "debug", "d", false, "Enable debug logging")

}
Expand Down
Loading

0 comments on commit 37b897b

Please sign in to comment.