jwt 0.7.0 → 0.7.1
raw patch · 7 files changed
+104/−55 lines, 7 filesbinary-added
Files
- CHANGELOG.md +50/−45
- jwt.cabal +3/−2
- src/Data/ByteString/Extended.hs +14/−0
- src/Web/JWT.hs +12/−8
- tests/jwt.secret.1 binary
- tests/src/TestRunner.hs +2/−0
- tests/src/Web/JWTTests.hs +23/−0
CHANGELOG.md view
@@ -1,86 +1,91 @@+# 2016-04-11 0.7.1++* Add `binarySecret` function to enable providing a secret based on a `ByteString`+ (fixes #21 - Thanks to Joe Nelson for reporting this).+ # 2016-02-20 0.7.0 - * Update JWT to match RFC 7519. This is a backward compatible change with- deprecation warnings added for types and functions to be removed in the- future.- * Add NumericDate as a replacement for IntDate (and numericDate as a - replacement for intDate)- * Add JOSEHeader as a replacement for JWTHeader.- * Use Stack and LTS 4.0- * Use cryptonite instead of cryptohash (Thanks to Greg V)- * Remove Web.Base64 in favour of using `memory` (Thanks to Greg V)+* Update JWT to match RFC 7519. This is a backward compatible change with+deprecation warnings added for types and functions to be removed in the+future.+ * Add NumericDate as a replacement for IntDate (and numericDate as a + replacement for intDate)+ * Add JOSEHeader as a replacement for JWTHeader.+* Use Stack and LTS 4.0+* Use cryptonite instead of cryptohash (Thanks to Greg V)+* Remove Web.Base64 in favour of using `memory` (Thanks to Greg V) # 2015-04-22 0.6.0 - * Execute doctests in addition to the testsuite when using 'make test'.- * Export `ClaimsMap` type alias (fixes #12)- * Allow base 4.8- * Lowered required cabal library version (to 1.16) to workaround build- issues in a consumer project.- * Add 7.10.1 to the travis config+* Execute doctests in addition to the testsuite when using 'make test'.+* Export `ClaimsMap` type alias (fixes #12)+* Allow base 4.8+* Lowered required cabal library version (to 1.16) to workaround build+ issues in a consumer project.+* Add 7.10.1 to the travis config # 2015-01-19 0.5.3 - * Add the missing `other-modules` field to the .cabal file so that - all the tests are present in the source distribution. Thanks to - Richard Wallace for reporting this.+* Add the missing `other-modules` field to the .cabal file so that + all the tests are present in the source distribution. Thanks to + Richard Wallace for reporting this. # 2015-01-17 0.5.2 - * Tim McLean pointed out that comparing signatures may be susceptible to- a timing attack in the way the signatures were compared (using the default- Eq instance). Both `Signature` and `Secret` now have an `Eq` instance that- uses a constant time comparison function. Thanks Tim for reporting this.+* Tim McLean pointed out that comparing signatures may be susceptible to+ a timing attack in the way the signatures were compared (using the default+ Eq instance). Both `Signature` and `Secret` now have an `Eq` instance that+ uses a constant time comparison function. Thanks Tim for reporting this. # 2015-01-03 0.5.1 - * Fix the encoding of the `aud` part of the claim.- Thanks to Aaron Levin for reporting and implementing the change.- In addition to the fix we now also verify the shape fo the generated- payload.+* Fix the encoding of the `aud` part of the claim.+ Thanks to Aaron Levin for reporting and implementing the change.+ In addition to the fix we now also verify the shape fo the generated+ payload. # 2014-12-01 0.5.0 - * Rev. 17 of the JWT Draft changed the audience claim from being an- optional String to being either an optional `StringOrURI`s or an optional list of- `StringOrURI`s. Thanks to Aaron Levin for reporting and implementing the- change. This change breaks backwards compatibility (in regard to 0.4.x).+* Rev. 17 of the JWT Draft changed the audience claim from being an+ optional String to being either an optional `StringOrURI`s or an optional list of+ `StringOrURI`s. Thanks to Aaron Levin for reporting and implementing the+ change. This change breaks backwards compatibility (in regard to 0.4.x). # 2014-10-15 0.4.2 - * Fix the build problems introduced in 0.4.1 to work with the - split network package. Thanks to Richard Wallace for- fixing this and to Jeremy Shaw for reporting this at the same time.+* Fix the build problems introduced in 0.4.1 to work with the + split network package. Thanks to Richard Wallace for+ fixing this and to Jeremy Shaw for reporting this at the same time. # 2014-09-17 0.4.1 - * Update jwt.cabal to work with the new split network package.- Thanks to Jeremy Shaw for reporting this.+* Update jwt.cabal to work with the new split network package.+ Thanks to Jeremy Shaw for reporting this. # 2014-08-02 0.4.0 - * Change the upper boundary of base from 4.7 to 4.8 (#5)+* Change the upper boundary of base from 4.7 to 4.8 (#5) # 2014-06-02 0.3.0 - * Add verify function (thanks to Robert Massaioli) to allow verifying an- already decoded JWT token+* Add verify function (thanks to Robert Massaioli) to allow verifying an+ already decoded JWT token # 2014-03-10 0.2.1 - * Add Decoding/Encoding sections- * Make the examples runnable by doctest- * Fix hlint warnings- * Add 'secondsSinceEpoch' to extract the seconds from epoch from an IntDate+* Add Decoding/Encoding sections+* Make the examples runnable by doctest+* Fix hlint warnings+* Add 'secondsSinceEpoch' to extract the seconds from epoch from an IntDate # 2014-03-10 0.2.0 - * Export the IntDate and StringOrURI types #5a1137b+* Export the IntDate and StringOrURI types #5a1137b # 2014-03-03 0.1.1 - * Verify that invalid input to the decode* functions fails as expected+* Verify that invalid input to the decode\* functions fails as expected # 2014-03-03 0.1.0 - * Initial release+* Initial release
jwt.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: jwt-version: 0.7.0+version: 0.7.1 synopsis: JSON Web Token (JWT) decoding and encoding license: MIT license-file: LICENSE@@ -22,6 +22,7 @@ extra-source-files: CHANGELOG.md README.md+ tests/jwt.secret.1 source-repository head type: git@@ -29,7 +30,7 @@ library exposed-modules: Web.JWT- other-modules: Data.Text.Extended+ other-modules: Data.Text.Extended, Data.ByteString.Extended build-depends: base >= 4.6 && < 4.9 , cryptonite >= 0.6 , memory >= 0.8
+ src/Data/ByteString/Extended.hs view
@@ -0,0 +1,14 @@+module Data.ByteString.Extended (+ module Data.ByteString+ , constTimeCompare+) where++import Data.Bits+import Data.ByteString+import qualified Data.List as L+import Prelude hiding (length, zip, zipWith)++constTimeCompare :: ByteString -> ByteString -> Bool+constTimeCompare l r = length l == length r && comp' l r+ where+ comp' a b = 0 == L.foldl' (.|.) 0 (uncurry xor <$> zip a b)
src/Web/JWT.hs view
@@ -40,6 +40,7 @@ -- ** Common , tokenIssuer , secret+ , binarySecret -- ** JWT structure , claims , header@@ -76,6 +77,7 @@ ) where import qualified Data.ByteString.Lazy.Char8 as BL (fromStrict, toStrict)+import qualified Data.ByteString.Extended as BS import qualified Data.Text.Extended as T import qualified Data.Text.Encoding as TE @@ -107,10 +109,10 @@ type JWTHeader = JOSEHeader -- | The secret used for calculating the message signature-newtype Secret = Secret T.Text+newtype Secret = Secret BS.ByteString instance Eq Secret where- (Secret s1) == (Secret s2) = s1 `T.constTimeCompare` s2+ (Secret s1) == (Secret s2) = s1 `BS.constTimeCompare` s2 instance Show Secret where show _ = "<secret>"@@ -353,13 +355,15 @@ tokenIssuer :: JSON -> Maybe StringOrURI tokenIssuer = decode >=> fmap pure claims >=> iss --- | Create a Secret using the given key--- This will currently simply wrap the given key appropriately buy may--- return a Nothing in the future if the key needs to adhere to a specific--- format and the given key is invalid.+-- | Create a Secret using the given key.+-- Consider using `binarySecret` instead if your key is not already a "Data.Text". secret :: T.Text -> Secret-secret = Secret+secret = Secret . TE.encodeUtf8 +-- | Create a Secret using the given key.+binarySecret :: BS.ByteString -> Secret+binarySecret = Secret+ -- | Convert the `NominalDiffTime` into an IntDate. Returns a Nothing if the -- argument is invalid (e.g. the NominalDiffTime must be convertible into a -- positive Integer representing the seconds since epoch).@@ -413,7 +417,7 @@ -- ================================================================================= calculateDigest :: Algorithm -> Secret -> T.Text -> T.Text-calculateDigest HS256 (Secret key) msg = TE.decodeUtf8 $ convertToBase Base64URLUnpadded (hmac (bs key) (bs msg) :: HMAC SHA256)+calculateDigest HS256 (Secret key) msg = TE.decodeUtf8 $ convertToBase Base64URLUnpadded (hmac key (bs msg) :: HMAC SHA256) where bs = TE.encodeUtf8
+ tests/jwt.secret.1 view
binary file changed (absent → 64 bytes)
tests/src/TestRunner.hs view
@@ -3,6 +3,7 @@ import qualified Web.JWTTests import qualified Web.JWTTestsCompat import qualified Web.JWTInteropTests+import qualified Data.ByteString.ExtendedTests import qualified Data.Text.ExtendedTests import Test.Tasty @@ -15,5 +16,6 @@ , Web.JWTTestsCompat.defaultTestGroup , Web.JWTInteropTests.defaultTestGroup , Data.Text.ExtendedTests.defaultTestGroup+ , Data.ByteString.ExtendedTests.defaultTestGroup ]
tests/src/Web/JWTTests.hs view
@@ -14,7 +14,9 @@ import qualified Test.QuickCheck as QC import qualified Data.Map as Map import qualified Data.Text as T+import qualified Data.Text.Encoding as TE import qualified Data.Text.Lazy as TL+import qualified Data.ByteString as BS import Data.Aeson.Types import Data.Maybe import Data.String (fromString, IsString)@@ -186,6 +188,17 @@ jwt = decodeAndVerifySignature secret' $ encodeSigned HS256 secret' cs Just cs @=? fmap claims jwt +case_encodeDecodeJWTClaimsSetBinarySecret = do+ let now = 1234+ cs = def {+ iss = stringOrURI "Foo"+ , iat = numericDate now+ }+ secretKey <- BS.readFile "tests/jwt.secret.1"+ let secret' = binarySecret secretKey+ jwt = decodeAndVerifySignature secret' $ encodeSigned HS256 secret' cs+ Just cs @=? fmap claims jwt+ prop_stringOrURIProp = f where f :: StringOrURI -> Bool f sou = let s = stringOrURI $ T.pack $ show sou@@ -203,12 +216,18 @@ f key claims' = let Just unverified = (decode $ encodeSigned HS256 (secret key) claims') in claims unverified == claims' +prop_encode_decode_binary_secret = f+ where f :: BS.ByteString -> JWTClaimsSet -> Bool+ f binary claims' = let Just unverified = (decode $ encodeSigned HS256 (binarySecret binary) claims')+ in claims unverified == claims'+ prop_encode_decode_verify_signature = f where f :: T.Text -> JWTClaimsSet -> Bool f key' claims' = let key = secret key' Just verified = (decodeAndVerifySignature key $ encodeSigned HS256 key claims') in claims verified == claims' + instance Arbitrary JWTClaimsSet where arbitrary = JWTClaimsSet <$> arbitrary <*> arbitrary@@ -234,6 +253,10 @@ arbitrary = fmap (f . stringOrURI) (arbitrary :: QC.Gen T.Text) where f = fromMaybe (fromJust $ stringOrURI "http://example.com")++instance Arbitrary BS.ByteString where+ arbitrary = BS.pack <$> arbitrary+ shrink xs = BS.pack <$> shrink (BS.unpack xs) instance Arbitrary T.Text where arbitrary = fromString <$> (arbitrary :: QC.Gen String)