Skip to content

Commit

Permalink
Output the duration used when it is overridden
Browse files Browse the repository at this point in the history
Newer versions of the CredHub server will include two new fields -
duration_overridden, which indicates the server-configured minimum was
used instead of the requested duration, and duration_used, which
indicates the final duration used to generate / regenerate the
certificate.

When these fields are present, and the duration_overridden flag is true,
the CLI will print out:
duration_overridden_to: X

with the value of the actual duration used.

Co-authored-by: Preethi Varambally <pvarambally@pivotal.io>
Co-authored-by: Brian Upton <bupton@vmware.com>
Co-authored-by: Pablo Rodas <prodas@vmware.com>
  • Loading branch information
3 people authored and bruce-ricard committed Sep 22, 2021
1 parent 03ba1c4 commit b3f83e4
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 16 deletions.
35 changes: 31 additions & 4 deletions commands/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import (
. "github.com/onsi/gomega/ghttp"
)

const generateRequestJSONWithMetadata = `{"type":"%s","name":"%s","parameters":%s,"overwrite":%t, "metadata":%s}`
const generateResponseJSONWithMetadata = `{"type":"%s","id":"` + uuid + `","name":"%s","version_created_at":"` + timestamp + `","value":%s,"metadata":%s}`
const generateResponseJSONWithDurationOverriddenFlag = `{"type":"%s","id":"` + uuid + `","name":"%s","version_created_at":"` + timestamp + `","value":%s,"duration_overridden":%v, "duration_used": 1460 }`

var _ = Describe("Generate", func() {
BeforeEach(func() {
login()
Expand Down Expand Up @@ -212,6 +216,7 @@ var _ = Describe("Generate", func() {
Eventually(session.Out).Should(Say("name: my-secret"))
Eventually(session.Out).Should(Say("type: certificate"))
Eventually(session.Out).Should(Say("value: <redacted>"))
Eventually(session.Out).ShouldNot(Say("duration_overridden_to:"))
})

It("allows the type to be any case", func() {
Expand Down Expand Up @@ -292,10 +297,25 @@ var _ = Describe("Generate", func() {
Eventually(session).Should(Exit(0))
})

It("including duration", func() {
It("including duration (missing duration_overridden in API response)", func() {
setupGenerateServer("certificate", "my-secret", `{"ca":"","certificate":"my-cert","private_key":"my-priv"}`, `{"duration":1000}`, true)
session := runCommand("generate", "-n", "my-secret", "-t", "certificate", "--duration", "1000")
Eventually(session).Should(Exit(0))
Eventually(session.Out).ShouldNot(Say("duration_overridden_to:"))
})

It("including duration less than minimum duration", func() {
setupGenerateServerWithDurationOverriddenFlag("certificate", "my-secret", `{"ca":"","certificate":"my-cert","private_key":"my-priv"}`, `{"duration":365}`, true, true)
session := runCommand("generate", "-n", "my-secret", "-t", "certificate", "--duration", "365")
Eventually(session).Should(Exit(0))
Eventually(session.Out).Should(Say("duration_overridden_to: 1460"))
})

It("including duration greater than minimum duration", func() {
setupGenerateServerWithDurationOverriddenFlag("certificate", "my-secret", `{"ca":"","certificate":"my-cert","private_key":"my-priv"}`, `{"duration":365}`, true, false)
session := runCommand("generate", "-n", "my-secret", "-t", "certificate", "--duration", "365")
Eventually(session).Should(Exit(0))
Eventually(session.Out).ShouldNot(Say("duration_overridden_to:"))
})

It("including certificate authority", func() {
Expand Down Expand Up @@ -552,9 +572,6 @@ func setupGenerateServer(keyType, name, generatedValue, params string, overwrite
)
}

const generateRequestJSONWithMetadata = `{"type":"%s","name":"%s","parameters":%s,"overwrite":%t, "metadata":%s}`
const generateResponseJSONWithMetadata = `{"type":"%s","id":"` + uuid + `","name":"%s","version_created_at":"` + timestamp + `","value":%s,"metadata":%s}`

func setupGenerateServerWithMetadata(keyType, name, generatedValue, params string, overwrite bool, metadata string) {
server.AppendHandlers(
CombineHandlers(
Expand All @@ -574,3 +591,13 @@ func setupGenerateServerWithValue(keyType, name, generatedValue, params, value s
),
)
}

func setupGenerateServerWithDurationOverriddenFlag(keyType, name, generatedValue, params string, overwrite bool, durationOverridden bool) {
server.AppendHandlers(
CombineHandlers(
VerifyRequest("POST", "/api/v1/data"),
VerifyJSON(fmt.Sprintf(generateRequestJSON, keyType, name, params, overwrite)),
RespondWith(http.StatusOK, fmt.Sprintf(generateResponseJSONWithDurationOverriddenFlag, keyType, name, generatedValue, durationOverridden)),
),
)
}
29 changes: 18 additions & 11 deletions credhub/credentials/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import (

// Base fields of a credential
type Base struct {
Id string `json:"id" yaml:"id"`
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
Metadata Metadata `json:"metadata" yaml:"metadata"`
VersionCreatedAt string `json:"version_created_at" yaml:"version_created_at"`
Id string `json:"id" yaml:"id"`
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
Metadata Metadata `json:"metadata" yaml:"metadata"`
VersionCreatedAt string `json:"version_created_at" yaml:"version_created_at"`
DurationOverridden bool `json:"duration_overridden,omitempty" yaml:"duration_overridden,omitempty"`
DurationUsed int `json:"duration_used,omitempty" yaml:"duration_used,omitempty"`
}

// Arbitrary metadata for credentials
Expand Down Expand Up @@ -44,12 +46,13 @@ func (c Credential) MarshalJSON() ([]byte, error) {

func (c Credential) convertToOutput() (interface{}, error) {
result := struct {
Id string `json:"id" yaml:"id"`
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
Value interface{} `json:"value"`
Metadata Metadata `json:"metadata" yaml:"metadata,omitempty"`
VersionCreatedAt string `json:"version_created_at" yaml:"version_created_at"`
Id string `json:"id" yaml:"id"`
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
Value interface{} `json:"value"`
Metadata Metadata `json:"metadata" yaml:"metadata,omitempty"`
VersionCreatedAt string `json:"version_created_at" yaml:"version_created_at"`
DurationOverriddenTo int `json:"duration_overridden_to,omitempty" yaml:"duration_overridden_to,omitempty"`
}{
Id: c.Id,
Name: c.Name,
Expand All @@ -58,6 +61,10 @@ func (c Credential) convertToOutput() (interface{}, error) {
VersionCreatedAt: c.VersionCreatedAt,
}

if c.Type == "certificate" && c.DurationOverridden {
result.DurationOverriddenTo = c.DurationUsed
}

_, ok := c.Value.(string)
if ok {
result.Value = c.Value
Expand Down
66 changes: 65 additions & 1 deletion credhub/credentials/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,70 @@ import (

var _ = Describe("Types", func() {
Describe("Certificate", func() {
Specify("when decoding and encoding", func() {
Specify("when decoding and encoding with duration_overridden and duration_used in the output", func() {
var cred Certificate

credJSON := `{
"id": "some-id",
"name": "/example-certificate",
"type": "certificate",
"duration_overridden": true,
"duration_used": 1234,
"value": {
"ca": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
},
"metadata": {"some":"metadata"},
"version_created_at": "2017-01-01T04:07:18Z"
}`
credYaml := `id: some-id
name: /example-certificate
type: certificate
duration_overridden: true
duration_used: 1234
value:
ca: |-
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
certificate: |-
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
private_key: |-
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
metadata:
some: metadata
version_created_at: 2017-01-01T04:07:18Z`

err := json.Unmarshal([]byte(credJSON), &cred)

Expect(err).To(BeNil())

Expect(cred.Id).To(Equal("some-id"))
Expect(cred.Name).To(Equal("/example-certificate"))
Expect(cred.Type).To(Equal("certificate"))
Expect(cred.DurationOverridden).To(Equal(true))
Expect(cred.DurationUsed).To(Equal(1234))
Expect(cred.Metadata).To(Equal(Metadata{"some": "metadata"}))
Expect(cred.Value.Ca).To(Equal("-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"))
Expect(cred.Value.Certificate).To(Equal("-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"))
Expect(cred.Value.PrivateKey).To(Equal("-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"))
Expect(cred.VersionCreatedAt).To(Equal("2017-01-01T04:07:18Z"))

jsonOutput, err := json.Marshal(cred)
Expect(err).NotTo(HaveOccurred())
Expect(jsonOutput).To(MatchJSON(credJSON))

yamlOutput, err := yaml.Marshal(cred)
Expect(err).NotTo(HaveOccurred())
Expect(yamlOutput).To(MatchYAML(credYaml))
})

Specify("when decoding and encoding with NO duration_overridden in the output", func() {
var cred Certificate

credJSON := `{
Expand Down Expand Up @@ -121,6 +184,7 @@ version_created_at: '2017-01-05T01:01:01Z'`
Expect(err).NotTo(HaveOccurred())
Expect(yamlOutput).To(MatchYAML(credYaml))
})

})

Describe("Password", func() {
Expand Down

0 comments on commit b3f83e4

Please sign in to comment.