module Network.HTTP.Lucu.Authentication
( AuthChallenge(..)
, AuthCredential(..)
, Realm
, UserID
, Password
)
where
import Control.Monad
import Data.Ascii (Ascii, AsciiBuilder)
import Data.Attempt
import Data.Attoparsec.Char8
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as C8
import Data.Convertible.Base
import Data.Convertible.Instances.Ascii ()
import Data.Convertible.Utils
import Data.Default
import Data.Monoid.Unicode
import Network.HTTP.Lucu.Parser.Http
import Network.HTTP.Lucu.Utils
import Prelude.Unicode
data AuthChallenge
= BasicAuthChallenge !Realm
deriving (Eq)
type Realm = Ascii
data AuthCredential
= BasicAuthCredential !UserID !Password
deriving (Show, Eq)
type UserID = Ascii
type Password = Ascii
instance ConvertSuccess AuthChallenge Ascii where
convertSuccess = convertSuccessVia ((⊥) ∷ AsciiBuilder)
instance ConvertSuccess AuthChallenge AsciiBuilder where
convertSuccess (BasicAuthChallenge realm)
= cs ("Basic realm=" ∷ Ascii) ⊕ quoteStr realm
deriveAttempts [ ([t| AuthChallenge |], [t| Ascii |])
, ([t| AuthChallenge |], [t| AsciiBuilder |])
]
instance Default (Parser AuthCredential) where
def = do void $ string "Basic"
skipMany1 lws
b64 ← takeWhile1 base64
case C8.break (≡ ':') (B64.decodeLenient b64) of
(user, cPassword)
| C8.null cPassword
→ fail "no colons in the basic auth credential"
| otherwise
→ do u ← asc user
p ← asc (C8.tail cPassword)
return (BasicAuthCredential u p)
where
base64 ∷ Char → Bool
base64 = inClass "a-zA-Z0-9+/="
asc ∷ C8.ByteString → Parser Ascii
asc bs
= case ca bs of
Success as → return as
Failure _ → fail "Non-ascii character in auth credential"