Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rotate logged in host api key #143

Merged
merged 4 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Nothing should go in this section, please add to the latest unreleased version
(and update the corresponding date), or add a new version.

## [8.0.11] - 2023-07-27
## [8.0.11] - 2023-08-25

### Fixed
- Handle trailing slash on appliance URL
[cyberark/conjur-cli-go#142](https://github.com/cyberark/conjur-cli-go/pull/142)
- Allow API key rotation for logged-in host
[cyberark/conjur-cli-go#143](https://github.com/cyberark/conjur-cli-go/pull/143)

## [8.0.10] - 2023-06-29

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
build:
go build -tags=dev -o ./dev/tmp/ ./cmd/conjur
go build -tags=dev -buildvcs=false -o ./dev/tmp/ ./cmd/conjur

test:
go test -tags=dev -count=1 -v ./...
Expand Down
20 changes: 19 additions & 1 deletion cmd/integration/host_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,33 @@ package main
import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func TestHostIntegration(t *testing.T) {
cli := newConjurTestCLI(t)
cli.InitAndLoginAsAdmin(t)

t.Run("rotate own api key", func(t *testing.T) {
cli.LoginAsHost(t, "bob")

stdOut, stdErr, err := cli.Run("whoami")
assert.Contains(t, stdOut, `"username": "host/bob"`)

priorApiKey := ""
stdOut, stdErr, err = cli.Run("host", "rotate-api-key")
assertAPIKeyRotationCmd(t, err, stdOut, stdErr, priorApiKey)
})

t.Run("rotate host api key", func(t *testing.T) {
cli.LoginAsAdmin(t)

stdOut, stdErr, err := cli.Run("whoami")
assert.Contains(t, stdOut, `"username": "admin"`)

priorAPIKey := ""
stdOut, stdErr, err := cli.Run("host", "rotate-api-key", "-i", fmt.Sprintf("%s:host:bob", cli.account))
stdOut, stdErr, err = cli.Run("host", "rotate-api-key", "-i", fmt.Sprintf("%s:host:bob", cli.account))
assertAPIKeyRotationCmd(t, err, stdOut, stdErr, priorAPIKey)

priorAPIKey = stdOut
Expand Down
5 changes: 5 additions & 0 deletions cmd/integration/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ func (cli *testConjurCLI) LoginAsAdmin(t *testing.T) {
assertLoginCmd(t, err, stdOut, stdErr)
}

func (cli *testConjurCLI) LoginAsHost(t *testing.T, host string) {
stdOut, stdErr, err := cli.Run("login", "-i", "host/"+host, "-p", makeDevRequest("retrieve_api_key", map[string]string{"role_id": cli.account + ":host:" + host}))
assertLoginCmd(t, err, stdOut, stdErr)
}

func (cli *testConjurCLI) LoadPolicy(t *testing.T, policyText string) {
stdOut, stdErr, err := cli.RunWithStdin(
bytes.NewReader([]byte(policyText)),
Expand Down
12 changes: 10 additions & 2 deletions pkg/cmd/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

type hostClient interface {
RotateHostAPIKey(hostID string) ([]byte, error)
RotateCurrentUserAPIKey() ([]byte, error)
}

type hostClientFactoryFunc func(*cobra.Command) (hostClient, error)
Expand Down Expand Up @@ -35,9 +36,10 @@ func newHostRotateAPIKeyCmd(clientFactory hostClientFactoryFunc) *cobra.Command
cmd := &cobra.Command{
Use: "rotate-api-key",
Short: "Rotate a host's API key",
Long: `Rotate the API key of the host specified by the [id] parameter.
Long: `Rotate the API key of the host specified by the [id] parameter or for the currently logged-in host if no [id] is provided.

Examples:
- conjur host rotate-api-key
- conjur host rotate-api-key --id ci-staging
- conjur host rotate-api-key --id host:ci-staging
- conjur host rotate-api-key --id dev:host:ci-staging`,
Expand All @@ -54,7 +56,13 @@ Examples:
return err
}

newAPIKey, err := client.RotateHostAPIKey(hostID)
var newAPIKey []byte
if hostID == "" {
newAPIKey, err = client.RotateCurrentUserAPIKey()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems if a user is logged in and ran 'conjur host rotate-api-key' it would also rotate the user's api key. I'm thinking in this case maybe we should fail with an error since that's probably not what the user wants to happen. They may be expecting usage info or something instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, the same is also true for conjur host rotate-api-key. This PR is addressing the particular reported bug. Perhaps we can address that in a separate PR

} else {
newAPIKey, err = client.RotateHostAPIKey(hostID)
}

if err != nil {
return err
}
Expand Down
46 changes: 31 additions & 15 deletions pkg/cmd/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,26 @@ import (
)

type mockHostClient struct {
t *testing.T
hostRotateAPIKey func(*testing.T, string) ([]byte, error)
t *testing.T
rotateCurrentUserAPIKey func() ([]byte, error)
rotateHostAPIKey func(*testing.T, string) ([]byte, error)
}

func (m mockHostClient) RotateCurrentUserAPIKey() ([]byte, error) {
return m.rotateCurrentUserAPIKey()
}

func (m mockHostClient) RotateHostAPIKey(hostID string) ([]byte, error) {
return m.hostRotateAPIKey(m.t, hostID)
return m.rotateHostAPIKey(m.t, hostID)
}

var hostRotateAPIKeyCmdTestCases = []struct {
name string
args []string
hostRotateAPIKey func(t *testing.T, hostID string) ([]byte, error)
clientFactoryError error
assert func(t *testing.T, stdout, stderr string, err error)
var rotateHostAPIKeyCmdTestCases = []struct {
name string
args []string
rotateCurrentUserAPIKey func() ([]byte, error)
rotateHostAPIKey func(t *testing.T, hostID string) ([]byte, error)
clientFactoryError error
assert func(t *testing.T, stdout, stderr string, err error)
}{
{
name: "without subcommand",
Expand All @@ -39,9 +45,19 @@ var hostRotateAPIKeyCmdTestCases = []struct {
},
},
{
name: "successful rotation",
name: "rotate API key for logged in host",
args: []string{"host", "rotate-api-key"},
rotateCurrentUserAPIKey: func() ([]byte, error) {
return []byte("test-api-key"), nil
},
assert: func(t *testing.T, stdout, stderr string, err error) {
assert.Contains(t, stdout, "test-api-key")
},
},
{
name: "rotate API key for specified host",
args: []string{"host", "rotate-api-key", "--id=dev-host"},
hostRotateAPIKey: func(t *testing.T, hostID string) ([]byte, error) {
rotateHostAPIKey: func(t *testing.T, hostID string) ([]byte, error) {
// Assert on arguments
assert.Equal(t, "dev-host", hostID)

Expand All @@ -54,7 +70,7 @@ var hostRotateAPIKeyCmdTestCases = []struct {
{
name: "client error",
args: []string{"host", "rotate-api-key", "--id=dev-host"},
hostRotateAPIKey: func(t *testing.T, hostID string) ([]byte, error) {
rotateHostAPIKey: func(t *testing.T, hostID string) ([]byte, error) {
return nil, fmt.Errorf("%s", "an error")
},
assert: func(t *testing.T, stdout, stderr string, err error) {
Expand All @@ -71,10 +87,10 @@ var hostRotateAPIKeyCmdTestCases = []struct {
},
}

func TestHostRotateAPIKeyCmd(t *testing.T) {
for _, tc := range hostRotateAPIKeyCmdTestCases {
func TestRotateHostAPIKeyCmd(t *testing.T) {
for _, tc := range rotateHostAPIKeyCmdTestCases {
t.Run(tc.name, func(t *testing.T) {
mockClient := mockHostClient{t: t, hostRotateAPIKey: tc.hostRotateAPIKey}
mockClient := mockHostClient{t: t, rotateHostAPIKey: tc.rotateHostAPIKey, rotateCurrentUserAPIKey: tc.rotateCurrentUserAPIKey}

cmd := newHostCmd(
func(cmd *cobra.Command) (hostClient, error) {
Expand Down