-
Notifications
You must be signed in to change notification settings - Fork 46
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
Parsing unprotected headers #123
Comments
Thanks for the report @ericpashman. I will review this in the coming days. |
@ericpashman can you please clarify the use case requirements? What fields are required, and where are they required to occur (protected header, or either header)? Does the application use compact serialisation, JSON serialisation, or either? |
This arose again in constructing a JWT for API access. The JWT header requires a nonce, and (I think) the nonce header can be either protected or unprotected. Compact serialization. |
@ericpashman I think all you need to do is: data MyHeader' p = MyHeader'
{ _myJWSHeader' :: JWSHeader p
, _myNonce' :: HeaderParam p UTCTime}
instance HasParams MyHeader' where
parseParamsFor proxy hp hu = MyHeader'
<$> parseParamsFor proxy hp hu
<*> headerRequiredProtected "nonce" hp hu See https://hackage.haskell.org/package/jose-0.11/docs/Crypto-JOSE-Header.html#g:2 for more explanation. The protection indicator is not something you need to deal with directly when parsing attributes. You use the relevant parsing function from the list below, according to whether the parameter is optional or required, and whether it must be carried in protected header or could be carried either protected or unprotected:
For serialisation, you can force a field to appear in the protected header regardless of the user-set protection value in hs-jose/src/Crypto/JOSE/JWS.hs Lines 334 to 363 in e81b0e9
|
Yes, as I mentioned, both of the examples I constructed work. My point in providing the second example is that it is "nicer", but that it requires a type definition for user-constructed custom headers that is different from what is recommended in the documentation. This was my (perhaps too subtle) way of suggesting that if you recommend that users define custom headers in this style, it may save them some aggravation. |
FYI, defining custom headers in the way I described at the end of the OP does type-check, but it does not in fact work. That is, this type-checks but ultimately leads to an invalid JWS: data MyHeader' p = MyHeader'
{ _myJWSHeader' :: JWSHeader p
, _myNonce' :: HeaderParam p UTCTime}
instance HasParams MyHeader' where
parseParamsFor proxy hp hu = MyHeader'
<$> parseParamsFor proxy hp hu
<*> headerRequired "nonce" hp hu You can pass this header type to On the one hand, yes, this is broken because I deliberately chose not to follow the instructions in the documentation about how to make a custom header type; on the other hand, it would be nice if this either (a) worked or (b) failed to type-check. As I mentioned in the OP, defining a header type in this way would be slightly nicer (if it worked) than the way the API presently requires, because it eliminates the need to give an explicit type signature to fix the protection indicator type. Note that users must include a type variable for the protection indicator in their custom header types (because the |
The
Crypto.JOSE.Header
module provides easy-to-use parsers for the case of protected headers, but it's less easy to use theheaderOptional
orheaderRequired
parsers when protection is not required.Unless I'm mistaken, parsing a custom header constructed in the recommended way requires first parsing it into a
HeaderParam p a
, then deconstructing theHeaderParam
(throwing away the protection indicator) to extract the actual header value.Here's a working example with a custom header type containing a nonce:
The difficulty is that the
ProtectionIndicator
type in the signature ofheaderRequired
(orheaderOptional
) must unify with the one in the signature ofparseParamsFor
. If it's possible to make that happen polymorphically without using any type-system extensions, I gave up before figuring it out. Fixing its type to either the monomorphic()
(as I did in the example) orProtection
works, but (a) you must write an explicit type signature on the parser, and (b) a monomorphic parser obviously will not work for both unprotected and protected headers.So unless I'm missing something, it seems like the module should just provide one set of parsers for explicitly protected headers (as it does), and another set for explicitly unprotected headers (as it doesn't). That would do away with both the need for explicit type signatures and for first parsing into the
HeaderParam
type. (If you don't know whether the header is protected or not, you would just try to parse one way, then the other.)Another way to go about this would be instead to recommend defining custom headers wrapped in the
HeaderParam
type. This would require all custom headers to have the sameProtectionIndicator
as the embeddedJWSHeader
, but it simplifies the parsing considerably. This works:The text was updated successfully, but these errors were encountered: