move BasicAuthData from servant-client to servant

This commit is contained in:
aaron levin 2016-01-26 23:45:35 +01:00
parent 738b9a8e9f
commit 459e82a8e0
7 changed files with 23 additions and 23 deletions

View file

@ -17,7 +17,6 @@
module Servant.Client module Servant.Client
( AuthClientData ( AuthClientData
, AuthenticateReq(..) , AuthenticateReq(..)
, BasicAuthData(..)
, client , client
, HasClient(..) , HasClient(..)
, mkAuthenticateReq , mkAuthenticateReq
@ -40,6 +39,7 @@ import Network.HTTP.Media
import qualified Network.HTTP.Types as H import qualified Network.HTTP.Types as H
import qualified Network.HTTP.Types.Header as HTTP import qualified Network.HTTP.Types.Header as HTTP
import Servant.API import Servant.API
import Servant.API.Auth (BasicAuthData)
import Servant.Common.Auth import Servant.Common.Auth
import Servant.Common.BaseUrl import Servant.Common.BaseUrl
import Servant.Common.Req import Servant.Common.Req

View file

@ -7,22 +7,15 @@
module Servant.Common.Auth ( module Servant.Common.Auth (
AuthenticateReq(AuthenticateReq, unAuthReq) AuthenticateReq(AuthenticateReq, unAuthReq)
, AuthClientData , AuthClientData
, BasicAuthData (BasicAuthData, username, password)
, basicAuthReq , basicAuthReq
, mkAuthenticateReq , mkAuthenticateReq
) where ) where
import Data.ByteString (ByteString)
import Data.ByteString.Base64 (encode) import Data.ByteString.Base64 (encode)
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.Text.Encoding (decodeUtf8) import Data.Text.Encoding (decodeUtf8)
import Servant.Common.Req (addHeader, Req) import Servant.Common.Req (addHeader, Req)
import Servant.API.Auth (BasicAuthData(BasicAuthData))
-- | A simple datatype to hold data required to decorate a request
data BasicAuthData = BasicAuthData { username :: ByteString
, password :: ByteString
}
-- | Authenticate a request using Basic Authentication -- | Authenticate a request using Basic Authentication
basicAuthReq :: BasicAuthData -> Req -> Req basicAuthReq :: BasicAuthData -> Req -> Req

View file

@ -51,6 +51,7 @@ import Test.HUnit
import Test.QuickCheck import Test.QuickCheck
import Servant.API import Servant.API
import Servant.API.Auth (BasicAuthData(BasicAuthData))
import Servant.API.Internal.Test.ComprehensiveAPI import Servant.API.Internal.Test.ComprehensiveAPI
import Servant.Client import Servant.Client
import Servant.Server import Servant.Server
@ -167,7 +168,7 @@ type instance AuthClientData (AuthProtect "auth-tag") = ()
basicAuthHandler :: BasicAuthCheck () basicAuthHandler :: BasicAuthCheck ()
basicAuthHandler = basicAuthHandler =
let check username password = let check (BasicAuthData username password) =
if username == "servant" && password == "server" if username == "servant" && password == "server"
then return (Authorized ()) then return (Authorized ())
else return Unauthorized else return Unauthorized

View file

@ -14,6 +14,7 @@ import GHC.Generics (Generic)
import Network.Wai.Handler.Warp (run) import Network.Wai.Handler.Warp (run)
import Servant.API ((:<|>) ((:<|>)), (:>), BasicAuth, import Servant.API ((:<|>) ((:<|>)), (:>), BasicAuth,
Get, JSON) Get, JSON)
import Servant.API.Auth (BasicAuthData(BasicAuthData))
import Servant.Server (AuthReturnType, BasicAuthResult (Authorized, Unauthorized), Config ((:.), EmptyConfig), import Servant.Server (AuthReturnType, BasicAuthResult (Authorized, Unauthorized), Config ((:.), EmptyConfig),
Server, serve, BasicAuthCheck(BasicAuthCheck)) Server, serve, BasicAuthCheck(BasicAuthCheck))
@ -59,7 +60,7 @@ type instance AuthReturnType (BasicAuth "foo-realm") = User
-- | 'BasicAuthCheck' holds the handler we'll use to verify a username and password. -- | 'BasicAuthCheck' holds the handler we'll use to verify a username and password.
authCheck :: BasicAuthCheck User authCheck :: BasicAuthCheck User
authCheck = authCheck =
let check username password = let check (BasicAuthData username password) =
if username == "servant" && password == "server" if username == "servant" && password == "server"
then return (Authorized (User "servant")) then return (Authorized (User "servant"))
else return Unauthorized else return Unauthorized

View file

@ -17,6 +17,7 @@ import GHC.Generics
import Network.HTTP.Types (Header) import Network.HTTP.Types (Header)
import Network.Wai (Request, requestHeaders) import Network.Wai (Request, requestHeaders)
import Servant.API.Auth (BasicAuthData(BasicAuthData))
import Servant.Server.Internal.RoutingApplication import Servant.Server.Internal.RoutingApplication
import Servant.Server.Internal.ServantErr import Servant.Server.Internal.ServantErr
@ -34,6 +35,8 @@ newtype AuthHandler r usr = AuthHandler
mkAuthHandler :: (r -> ExceptT ServantErr IO usr) -> AuthHandler r usr mkAuthHandler :: (r -> ExceptT ServantErr IO usr) -> AuthHandler r usr
mkAuthHandler = AuthHandler mkAuthHandler = AuthHandler
-- * Basic Auth
-- | The result of authentication/authorization -- | The result of authentication/authorization
data BasicAuthResult usr data BasicAuthResult usr
= Unauthorized = Unauthorized
@ -42,11 +45,9 @@ data BasicAuthResult usr
| Authorized usr | Authorized usr
deriving (Eq, Show, Read, Generic, Typeable, Functor) deriving (Eq, Show, Read, Generic, Typeable, Functor)
-- * Basic Auth
newtype BasicAuthCheck usr = BasicAuthCheck newtype BasicAuthCheck usr = BasicAuthCheck
{ unBasicAuthCheck :: BS.ByteString -- Username { unBasicAuthCheck :: BasicAuthData
-> BS.ByteString -- Password
-> IO (BasicAuthResult usr) -> IO (BasicAuthResult usr)
} }
deriving (Generic, Typeable, Functor) deriving (Generic, Typeable, Functor)
@ -55,7 +56,7 @@ mkBAChallengerHdr :: BS.ByteString -> Header
mkBAChallengerHdr realm = ("WWW-Authenticate", "Basic realm=\"" <> realm <> "\"") mkBAChallengerHdr realm = ("WWW-Authenticate", "Basic realm=\"" <> realm <> "\"")
-- | Find and decode an 'Authorization' header from the request as Basic Auth -- | Find and decode an 'Authorization' header from the request as Basic Auth
decodeBAHdr :: Request -> Maybe (BS.ByteString, BS.ByteString) decodeBAHdr :: Request -> Maybe BasicAuthData
decodeBAHdr req = do decodeBAHdr req = do
ah <- lookup "Authorization" $ requestHeaders req ah <- lookup "Authorization" $ requestHeaders req
let (b, rest) = BS.break isSpace ah let (b, rest) = BS.break isSpace ah
@ -63,13 +64,13 @@ decodeBAHdr req = do
let decoded = decodeLenient (BS.dropWhile isSpace rest) let decoded = decodeLenient (BS.dropWhile isSpace rest)
let (username, passWithColonAtHead) = BS.break (== _colon) decoded let (username, passWithColonAtHead) = BS.break (== _colon) decoded
(_, password) <- BS.uncons passWithColonAtHead (_, password) <- BS.uncons passWithColonAtHead
return (username, password) return (BasicAuthData username password)
runBasicAuth :: Request -> BS.ByteString -> BasicAuthCheck usr -> IO (RouteResult usr) runBasicAuth :: Request -> BS.ByteString -> BasicAuthCheck usr -> IO (RouteResult usr)
runBasicAuth req realm (BasicAuthCheck ba) = runBasicAuth req realm (BasicAuthCheck ba) =
case decodeBAHdr req of case decodeBAHdr req of
Nothing -> plzAuthenticate Nothing -> plzAuthenticate
Just e -> uncurry ba e >>= \res -> case res of Just e -> ba e >>= \res -> case res of
BadPassword -> plzAuthenticate BadPassword -> plzAuthenticate
NoSuchUser -> plzAuthenticate NoSuchUser -> plzAuthenticate
Unauthorized -> return $ Fail err403 Unauthorized -> return $ Fail err403

View file

@ -33,7 +33,7 @@ import Network.HTTP.Types (Status (..), hAccept, hContentType,
import Network.Wai (Application, Request, requestHeaders, pathInfo, import Network.Wai (Application, Request, requestHeaders, pathInfo,
queryString, rawQueryString, queryString, rawQueryString,
responseBuilder, responseLBS) responseBuilder, responseLBS)
import Network.Wai.Internal (Response (ResponseBuilder), requestHeaders) import Network.Wai.Internal (Response (ResponseBuilder))
import Network.Wai.Test (defaultRequest, request, import Network.Wai.Test (defaultRequest, request,
runSession, simpleBody, runSession, simpleBody,
simpleHeaders, simpleStatus) simpleHeaders, simpleStatus)
@ -55,20 +55,18 @@ import qualified Test.Hspec.Wai as THW
import Test.Hspec.Wai (get, liftIO, matchHeaders, import Test.Hspec.Wai (get, liftIO, matchHeaders,
matchStatus, request, matchStatus, request,
shouldRespondWith, with, (<:>)) shouldRespondWith, with, (<:>))
import qualified Test.Hspec.Wai as THW
import Servant.API.Auth (BasicAuthData(BasicAuthData))
import Servant.Server.Internal.Auth import Servant.Server.Internal.Auth
(AuthHandler, AuthReturnType, BasicAuthCheck (BasicAuthCheck), (AuthHandler, AuthReturnType, BasicAuthCheck (BasicAuthCheck),
BasicAuthResult (Authorized, Unauthorized), mkAuthHandler) BasicAuthResult (Authorized, Unauthorized), mkAuthHandler)
import Servant.Server.Internal.Auth
import Servant.Server.Internal.RoutingApplication import Servant.Server.Internal.RoutingApplication
(toApplication, RouteResult(..)) (toApplication, RouteResult(..))
import Servant.Server.Internal.Router import Servant.Server.Internal.Router
(tweakResponse, runRouter, (tweakResponse, runRouter,
Router, Router'(LeafRouter)) Router, Router'(LeafRouter))
import Servant.Server.Internal.Config import Servant.Server.Internal.Config
(Config(..), NamedConfig(..)) (NamedConfig(NamedConfig))
-- * comprehensive api test -- * comprehensive api test
@ -554,7 +552,7 @@ authConfig :: Config '[ BasicAuthCheck ()
, AuthHandler Request () , AuthHandler Request ()
] ]
authConfig = authConfig =
let basicHandler = BasicAuthCheck $ (\usr pass -> let basicHandler = BasicAuthCheck $ (\(BasicAuthData usr pass) ->
if usr == "servant" && pass == "server" if usr == "servant" && pass == "server"
then return (Authorized ()) then return (Authorized ())
else return Unauthorized else return Unauthorized

View file

@ -4,6 +4,7 @@
{-# LANGUAGE PolyKinds #-} {-# LANGUAGE PolyKinds #-}
module Servant.API.Auth where module Servant.API.Auth where
import Data.ByteString (ByteString)
import Data.Typeable (Typeable) import Data.Typeable (Typeable)
import GHC.TypeLits (Symbol) import GHC.TypeLits (Symbol)
@ -20,6 +21,11 @@ import GHC.TypeLits (Symbol)
data BasicAuth (realm :: Symbol) data BasicAuth (realm :: Symbol)
deriving (Typeable) deriving (Typeable)
-- | A simple datatype to hold data required to decorate a request
data BasicAuthData = BasicAuthData { basicAuthUsername :: !ByteString
, basicAuthPassword :: !ByteString
}
-- | A generalized Authentication combinator. -- | A generalized Authentication combinator.
data AuthProtect (tag :: k) data AuthProtect (tag :: k)
deriving (Typeable) deriving (Typeable)