-
Notifications
You must be signed in to change notification settings - Fork 123
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
Updated how batch secrets are rendered in JSON #1989
Conversation
7d58399
to
34b4c2f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should definitely be reviewed by @cyberark/conjur-core-team, but I wanted to note that this dependency is fine to add since it's available under MIT. We just need to add its license to the NOTICES.txt file in this project, and should probably do so in this PR: https://github.com/brianmario/yajl-ruby/blob/1.4.1/LICENSE
the PR is also missing a CHANGELOG message explaining the change that was made and the impact to the end user.
34b4c2f
to
2db4231
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@telday are there any tests we can add so that we can verify this functionality corrects the reported issue?
I actually find it really helpful in cases like this to add broken test(s) so that I can be sure that my updated functionality addresses the issue (eg the tests go green with my fix).
in this case, I'd guess we could manually create a truststore.p12
file using openssl pkcs12 -in truststore.p12 -nodes | openssl x509 -noout -enddate
, add that to the repo test dir, and then add a test that loads that into a variable and attempts to retrieve it via the batch retrieval endpoint / read the output
@izgeri @orenbm On a second pass looking at this issue I may need a little more guidance in order to fix it. The biggest issue is encoding secrets in JSON, which has no support for a The second approach I tried to take was to encode the byte data of the secret as an array of integers in the JSON. However this doesn't seem like a great solution, users would most likely be very confused especially if retrieving the secret individually returns just the raw data. This also forces all binary secrets to have their mime type annotation specified. Have I missed something that would make this significantly easier? |
@telday I like the idea of the batch retrieval endpoint specifying the mimetype for each secret retrieved (or grouping them by mimetype to reduce duplication). Such an approach would be consistent with the endpoint for single secret retrieval. Re: encodings, when I first saw this issue I thought BSON might be useful here, see http://bsonspec.org/implementations.html. It's a lot more flexible than JSON. But it might also be overkill. Things like bytes can be represented as arrays (though maybe not the most efficient representation) as long as there's metadata to allow us to recover the original. |
2db4231
to
529f67a
Compare
Just wanted to throw out my implementation plan for fixing this. I looked into using BSON for encoding the result, however because it is not a strict superset of JSON I think it would be too much to ask all users to switch to using a BSON library when they are not often built into languages. So what I am going to implement is checking the mime_type annotation for each secret, and if it is the e.g. {
"cucumber:variable:secret2": "v2",
"application/octet-stream": {
"cucumber:variable:secret3": "d/U4bDbw3WQzYW5O7AcZzQ==\n",
"encoding": "base64"
}
} It is not a perfect solution, however I think it is the right way to go for two main reasons:
This does mean that all binary secrets will need to have the Let me know what you think/if anything needs to be changed. I coded up most of this as well as added a cucumber. |
176b0fb
to
c132903
Compare
c132903
to
fcee1d1
Compare
c3ba6c1
to
2b4b8d2
Compare
@@ -276,6 +280,16 @@ def render_record_not_found e | |||
}, status: :not_found | |||
end | |||
|
|||
def bad_secret_encoding e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar blocks of code found in 2 locations. Consider refactoring.
|
||
if mime_type == 'application/octet-stream' | ||
unless result.key?('application/octet-stream') | ||
result['application/octet-stream'] = { 'encoding': 'base64' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think base64 encoding is robust enough to address the current issue and potentially moving forward. With that in mind, perhaps we can always and only base64 encode values and always specify the mimeType. This throws out any space savings etc., but I don't think that's altogether necessary and might really just be premature optimisation. The response payload might look something like this.
By avoiding sending raw values we don't ever have to know or reason about what is inside.
{
"id/of/secret": {
"base64value": "",
"mimeType": ""
},
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of encoding all secrets in base64, and we could group by mime type in order to reduce duplication in the JSON. It would be more consistent and resolve this issue in a cleaner manner so I would prefer it. The reason I didn't include it in this PR is because it would definitely be a breaking change for users. If we are willing to deal with the change being breaking then I can definitely put it in.
@telday given what you've implemented, and to help people understand the impact of this change, can you please update the PR description to include an example of what the response looks like now vs what it will look like after this change? I am trying to understand whether this is a breaking change, and it's hard to tell from what's written here. |
a444bed
to
7b755a1
Compare
# frozen_string_literal: true | ||
|
||
module Exceptions | ||
class BadSecretEncoding < EncodingError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exceptions::BadSecretEncoding has no descriptive comment
7b755a1
to
bb9dff6
Compare
|
||
secret_value = secret.value | ||
|
||
if request.headers['Accept'].casecmp? 'base64' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CodeClimate should be flagging this for missing parens.
# frozen_string_literal: true | ||
|
||
module Exceptions | ||
class BadSecretEncoding < EncodingError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exceptions::BadSecretEncoding has no descriptive comment
bb9dff6
to
910ff91
Compare
# frozen_string_literal: true | ||
|
||
module Exceptions | ||
class BadSecretEncoding < EncodingError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exceptions::BadSecretEncoding has no descriptive comment
910ff91
to
2bcc031
Compare
Allows for binary secrets to be encoded nicely in a batch result without causing a server side error
2bcc031
to
58e6535
Compare
Code Climate has analyzed commit 58e6535 and detected 0 issues on this pull request. The test coverage on the diff in this pull request is 100.0% (50% is the threshold). This pull request will bring the total coverage in the repository to 89.2% (0.0% change). View more on Code Climate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work on this @telday!! Thanks for sticking with it!
@saprette going open an issue and change the requests this morning |
@telday @doodlesbykumbi @izgeri: This solution cleverly handles backwards compatibility, which is excellent. But is it slightly abusing the Also, as a reminder, please be sure to file a documentation ticket when adding/changing product behavior. Thanks! |
@alexkalish and I connected on this, and we're not going to include this in the documentation until we find a satisfying answer to the question he raised above ^ Please also note that the behavior was changed in #2065 to use |
@alexkalish I agree that it is to some extent an abuse of the |
What does this PR do?
Changed how binary secrets are rendered in batch requests.
Some Details on the Implementation:
Based on feedback in a slack discussion I have moved to a different solution for this issue.
Now on requests to the batch secrets endpoint Conjur will read the
Accept
header from the request. Currently if the header isbase64
it will encode all of the secrets inbase64
and return them in the same JSON format we currently use. If the header is set to anything else (or not set at all) the endpoint will act as it has previously, except now returning a 501 with an error message to the user. The up side of this approach is that it will maintain compatibility and is a simple implementation.Here is an example of a returned JSON object with the
Accept: base64
header set:The original value of secret2 was
"v2"
and secret3 was binary data.I also included a conversion of the header value to lowercase to avoid issues between
base64
andBase64
because I know some people prefer one over the other.What ticket does this PR close?
Resolves #1962
Checklists
Change log
Test coverage
Documentation
README
s) were updated in this PR, and/or there is a follow-on issue to update docs, or