diff --git a/commands/generate_test.go b/commands/generate_test.go index 962fb430..457b4916 100644 --- a/commands/generate_test.go +++ b/commands/generate_test.go @@ -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() @@ -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: ")) + Eventually(session.Out).ShouldNot(Say("duration_overridden_to:")) }) It("allows the type to be any case", func() { @@ -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() { @@ -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( @@ -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)), + ), + ) +} diff --git a/credhub/credentials/types.go b/credhub/credentials/types.go index 6061c1d9..c8e8a15b 100644 --- a/credhub/credentials/types.go +++ b/credhub/credentials/types.go @@ -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 @@ -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, @@ -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 diff --git a/credhub/credentials/types_test.go b/credhub/credentials/types_test.go index b5953cc3..79d523c9 100644 --- a/credhub/credentials/types_test.go +++ b/credhub/credentials/types_test.go @@ -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 := `{ @@ -121,6 +184,7 @@ version_created_at: '2017-01-05T01:01:01Z'` Expect(err).NotTo(HaveOccurred()) Expect(yamlOutput).To(MatchYAML(credYaml)) }) + }) Describe("Password", func() {