Skip to content

Commit

Permalink
Merge "[FAB-4097] Fix getcacert client command config"
Browse files Browse the repository at this point in the history
  • Loading branch information
christo4ferris authored and Gerrit Code Review committed May 31, 2017
2 parents 0f73bdc + 1777996 commit 2c45212
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 38 deletions.
53 changes: 53 additions & 0 deletions cmd/fabric-ca-client/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"strings"
)

const (
client = "client"
enroll = "enroll"
reenroll = "reenroll"
register = "register"
revoke = "revoke"
getcacert = "getcacert"
)

// Command is the object for fabric-ca-client commands
type Command struct {
name string
}

// NewCommand will return command type
func NewCommand(commandName string) *Command {
return &Command{
name: strings.ToLower(commandName),
}
}

// Certain client commands can only be executed if enrollment credentials
// are present
func (cmd *Command) requiresEnrollment() bool {
return cmd.name != enroll && cmd.name != getcacert
}

// Create default client configuration file only during an enroll command
func (cmd *Command) shouldCreateDefaultConfig() bool {
return cmd.name == enroll
}
46 changes: 36 additions & 10 deletions cmd/fabric-ca-client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ var (
func configInit(command string) error {
var err error

cmd := NewCommand(command)

if cfgFileName != "" {
log.Infof("User provided config file: %s\n", cfgFileName)
}
Expand All @@ -224,30 +226,40 @@ func configInit(command string) error {
}
}

if command != "enroll" {
// Commands other than 'enroll' and 'getcacert' require that client already
// be enrolled
if cmd.requiresEnrollment() {
err = checkForEnrollment()
if err != nil {
return err
}
}

// If the config file doesn't exist, create a default one
if !util.FileExists(cfgFileName) {
err = createDefaultConfigFile()
if err != nil {
return fmt.Errorf("Failed to create default configuration file: %s", err)
// If the config file doesn't exist, create a default one if enroll
// command being executed. Enroll should be the first command to be
// executed, and furthermore the default configuration file requires
// enrollment ID to populate CN field which is something the enroll
// command requires
if cmd.shouldCreateDefaultConfig() {
if !util.FileExists(cfgFileName) {
err = createDefaultConfigFile()
if err != nil {
return fmt.Errorf("Failed to create default configuration file: %s", err)
}
log.Infof("Created a default configuration file at %s", cfgFileName)
}
log.Infof("Created a default configuration file at %s", cfgFileName)
} else {
log.Infof("Configuration file location: %s", cfgFileName)
}

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

// Unmarshal the config into 'clientCfg'
Expand Down Expand Up @@ -282,6 +294,9 @@ func configInit(command string) error {
return err
}

// Check for separaters and insert values back into slice
normalizeStringSlices()

return nil
}

Expand Down Expand Up @@ -344,3 +359,14 @@ func checkForEnrollment() error {
}
return client.CheckEnrollment()
}

func normalizeStringSlices() {
fields := []*[]string{
&clientCfg.CSR.Hosts,
&clientCfg.TLS.CertFiles,
}
for _, namePtr := range fields {
norm := util.NormalizeStringSlice(*namePtr)
*namePtr = norm
}
}
30 changes: 19 additions & 11 deletions cmd/fabric-ca-client/enroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,29 @@ var enrollCmd = &cobra.Command{
Use: "enroll -u http://user:userpw@serverAddr:serverPort",
Short: "Enroll an identity",
Long: "Enroll identity with fabric-ca server",
RunE: func(cmd *cobra.Command, args []string) error {
// PreRunE block for this command will check to make sure username
// and secret provided for the enroll command before creating and/or
// reading configuration file
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf(extraArgsError, args, cmd.UsageString())
}

_, _, err := util.GetUser()
if err != nil {
return err
}

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 {
err := runEnroll(cmd)
if err != nil {
return err
Expand All @@ -57,16 +75,6 @@ func init() {
// The client enroll main logic
func runEnroll(cmd *cobra.Command) error {
log.Debug("Entered runEnroll")
_, _, err := util.GetUser()
if err != nil {
return err
}

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

resp, err := clientCfg.Enroll(clientCfg.URL, filepath.Dir(cfgFileName))
if err != nil {
return err
Expand Down
16 changes: 16 additions & 0 deletions cmd/fabric-ca-client/getcacert.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ import (
var getCACertCmd = &cobra.Command{
Use: "getcacert -u http://serverAddr:serverPort -M <MSP-directory>",
Short: "Get CA certificate chain",
// PreRunE block for this command will load client configuration
// before running the command
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf(extraArgsError, args, cmd.UsageString())
}

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 {
return fmt.Errorf(extraArgsError, args, cmd.UsageString())
Expand Down
74 changes: 57 additions & 17 deletions cmd/fabric-ca-client/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"

"github.com/cloudflare/cfssl/config"
"github.com/hyperledger/fabric-ca/api"
"github.com/hyperledger/fabric-ca/lib"
"github.com/hyperledger/fabric-ca/lib/dbutil"
Expand Down Expand Up @@ -385,7 +383,7 @@ func testRegisterEnvVar(t *testing.T) {

os.Unsetenv("FABRIC_CA_CLIENT_ID_NAME")
os.Unsetenv("FABRIC_CA_CLIENT_ID_AFFILIATION")
os.Unsetenv("FABRIC_CA_CLIENT_TLS_ID_TYPE")
os.Unsetenv("FABRIC_CA_CLIENT_ID_TYPE")

os.Remove(defYaml)
}
Expand Down Expand Up @@ -561,6 +559,38 @@ func testBogus(t *testing.T) {
}
}

func TestGetCACert(t *testing.T) {
srv = getServer()
srv.Config.Debug = true

// Configure TLS settings on server
srv.HomeDir = tdDir
srv.Config.TLS.Enabled = true
srv.Config.TLS.CertFile = tlsCertFile
srv.Config.TLS.KeyFile = tlsKeyFile

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

// Test getcacert command using environment variables to set root TLS cert
err = testGetCACertEnvVar(t)
assert.NoError(t, err, "Failed to get CA cert using environment variables")

// Change client authentication type on server
srv.Config.TLS.ClientAuth.Type = "RequireAndVerifyClientCert"

// Test getcacert command using configuration files to read in client TLS cert and key
err = testGetCACertConfigFile(t)
assert.NoError(t, err, "Failed to get CA cert using client configuration file")

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

func TestClientCommandsUsingConfigFile(t *testing.T) {
os.Remove(fabricCADB)

Expand Down Expand Up @@ -778,6 +808,30 @@ func TestRegisterWithoutEnroll(t *testing.T) {
}
}

func testGetCACertEnvVar(t *testing.T) error {
t.Log("testGetCACertEnvVar - Entered")
os.Setenv(rootCertEnvVar, "../../testdata/root.pem")

err := RunMain([]string{cmdName, "getcacert", "-d", "-c", "fakeConfig.yaml", "-u", "https://localhost:7054", "--tls.client.certfile", "", "--tls.client.keyfile", "", "--caname", ""})
if err != nil {
return fmt.Errorf("getcainfo failed: %s", err)
}

return nil
}

func testGetCACertConfigFile(t *testing.T) error {
t.Log("testGetCACertConfigFile - Entered")
configFile := "../../testdata/fabric-ca-client-config.yaml"

err := RunMain([]string{cmdName, "getcacert", "-d", "-c", configFile, "-u", "https://localhost:7054", "--tls.certfiles", rootCert})
if err != nil {
return fmt.Errorf("getcainfo failed: %s", err)
}

return nil
}

func getServer() *lib.Server {
return &lib.Server{
HomeDir: ".",
Expand All @@ -800,16 +854,6 @@ func getCAConfig() *lib.CAConfig {
"org1": nil,
}

defaultSigningProfile := &config.SigningProfile{
Usage: []string{"cert sign"},
ExpiryString: "8000h",
Expiry: time.Hour * 8000,
}

profiles := map[string]*config.SigningProfile{
"ca": defaultSigningProfile,
}

return &lib.CAConfig{
CA: lib.CAInfo{
Keyfile: keyfile,
Expand All @@ -819,10 +863,6 @@ func getCAConfig() *lib.CAConfig {
CSR: api.CSRInfo{
CN: "TestCN",
},
Signing: &config.Signing{
Default: defaultSigningProfile,
Profiles: profiles,
},
}
}

Expand Down

0 comments on commit 2c45212

Please sign in to comment.