packages feed

servant-auth-token 0.5.4.0 → 0.5.5.0

raw patch · 4 files changed

+48/−4 lines, 4 filesdep +byteablePVP ok

version bump matches the API change (PVP)

Dependencies added: byteable

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,3 +1,8 @@+0.5.5.0+=======++* Allow passing client side hashed password to signin endpoint. + 0.5.4.0 ======= 
servant-auth-token.cabal view
@@ -1,5 +1,5 @@ name:                servant-auth-token-version:             0.5.4.0+version:             0.5.5.0 synopsis:            Servant based API and server for token based authorisation description:         Please see README.md homepage:            https://github.com/ncrashed/servant-auth-token#readme@@ -62,6 +62,7 @@   build-depends:       base                    >= 4.8    && < 5     , aeson-injector          >= 1.1    && < 1.2+    , byteable                >= 0.1    && < 0.2     , bytestring              >= 0.10   && < 0.11     , containers              >= 0.5    && < 0.6     , http-api-data           >= 0.3.5  && < 0.4
src/Servant/Server/Auth/Token.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE UndecidableInstances #-} {-| Module      : Servant.Server.Auth.Token@@ -78,6 +79,7 @@ import Crypto.PasswordStore import Data.Aeson.Unit import Data.Aeson.WithField+import Data.Byteable (Byteable, toBytes, constEqBytes) import Data.Maybe import Data.Monoid import Data.Text (Text)@@ -98,6 +100,7 @@ import Servant.Server.Auth.Token.Restore import Servant.Server.Auth.Token.SingleUse +import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy as BS  -- | Implementation of AuthAPI@@ -128,7 +131,18 @@   :<|> authGetUserIdMethod   :<|> authFindUserByLogin --- | Implementation of "signin" method+-- | Implementation of "signin" method.+--+-- You can pass hashed password in format of `pwstore`. The library will+-- strengthen the hash and compare with hash in DB in this case. The feature+-- allow you to previously hash on client side to not pass the password as plain+-- text to server. Note that you should have the same salt in the passwords.+--+-- Also avoid having strength of hashed password less that is passed from client side.+--+-- Format of hashed password: "sha256|strength|salt|hash", where strength is an unsigned int, salt+-- is a base64-encoded 16-byte random number, and hash is a base64-encoded hash+-- value. authSignin :: AuthHandler m   => Maybe Login -- ^ Login query parameter   -> Maybe Password -- ^ Password query parameter@@ -140,14 +154,38 @@   WithField uid UserImpl{..} <- guardLogin login pass   OnlyField <$> getAuthToken uid mexpire   where+  checkPassword pass uimpl@UserImpl{..} = case readPwHash pass of+    Nothing -> pass `verifyPassword` passToByteString userImplPassword+    Just (passedStrength, passedSalt, passedHash) -> case readPwHash $ passToByteString userImplPassword of+      Nothing -> False+      Just (storedStrength, storedSalt, storedHash) -> if+        | not (passedSalt `constEqBytes` storedSalt) -> False+        | passedStrength == storedStrength -> passedHash `constEqBytes` storedHash+        | passedStrength < storedStrength -> let+            newPass = strengthenPassword pass storedStrength+            in checkPassword newPass uimpl+        | otherwise -> let+            newUserPass = strengthenPassword (passToByteString userImplPassword) passedStrength+            in checkPassword pass uimpl { userImplPassword = byteStringToPass newUserPass }   guardLogin login pass = do -- check login and password, return passed user     muser <- getUserImplByLogin login     let err = throw401 "Cannot find user with given combination of login and pass"     case muser of       Nothing -> err-      Just user@(WithField _ UserImpl{..}) -> if passToByteString pass `verifyPassword` passToByteString userImplPassword+      Just user@(WithField _ uimpl) -> if checkPassword (passToByteString pass) uimpl         then return user         else err++-- | Try to parse a password hash.+readPwHash :: BC.ByteString -> Maybe (Int, BC.ByteString, BC.ByteString)+readPwHash pw | length broken /= 4+                || algorithm /= "sha256"+                || BC.length hash /= 44 = Nothing+              | otherwise = case BC.readInt strBS of+                              Just (strength, _) -> Just (strength, salt, hash)+                              Nothing -> Nothing+    where broken = BC.split '|' pw+          [algorithm, strBS, salt, hash] = broken  -- | Implementation of "signin" method authSigninPost :: AuthHandler m
stack.yaml view
@@ -43,7 +43,7 @@ #- 'servant-auth-token-rocksdb' - 'example/acid' - 'example/persistent'-#- 'example/leveldb'+- 'example/leveldb' #- '../servant-auth-token-api' # - location: #     git: https://github.com/NCrashed/servant-auth-token-api.git