]> gitweb @ CieloNegro.org - Lucu.git/commitdiff
added facilities for basic authentication (not tested)
authorpho <pho@cielonegro.org>
Thu, 10 Jan 2008 05:54:20 +0000 (14:54 +0900)
committerpho <pho@cielonegro.org>
Thu, 10 Jan 2008 05:54:20 +0000 (14:54 +0900)
darcs-hash:20080110055420-62b54-3f799b4e91fe6ad19a36874a0e22ad1c46c935cb.gz

Lucu.cabal
Network/HTTP/Lucu/Authorization.hs [new file with mode: 0644]
Network/HTTP/Lucu/Resource.hs

index e545e99ade1f3e0b7d4220270c41b9f62c19bed0..5ee1f72dfec01a0036b838a132a9e9fdd34901f4 100644 (file)
@@ -35,6 +35,7 @@ Library
     Exposed-Modules:
         Network.HTTP.Lucu
         Network.HTTP.Lucu.Abortion
+        Network.HTTP.Lucu.Authorization
         Network.HTTP.Lucu.Config
         Network.HTTP.Lucu.ETag
         Network.HTTP.Lucu.HttpVersion
diff --git a/Network/HTTP/Lucu/Authorization.hs b/Network/HTTP/Lucu/Authorization.hs
new file mode 100644 (file)
index 0000000..bcc8003
--- /dev/null
@@ -0,0 +1,66 @@
+-- #prune
+
+-- |Manipulation of WWW authorization.
+module Network.HTTP.Lucu.Authorization
+    ( AuthChallenge(..)
+    , AuthCredential(..)
+    , Realm
+    , UserID
+    , Password
+
+    , authCredentialP -- private
+    )
+    where
+
+import qualified Codec.Binary.Base64 as B64
+import           Network.HTTP.Lucu.Parser
+import           Network.HTTP.Lucu.Parser.Http
+import           Network.HTTP.Lucu.Utils
+
+-- |Authorization challenge to be sent to client with
+-- \"WWW-Authenticate\" header. See
+-- 'Network.HTTP.Lucu.Resource.setWWWAuthenticate'.
+data AuthChallenge
+    = BasicAuthChallenge Realm
+      deriving (Eq)
+
+-- |'Realm' is just a string which must not contain any non-ASCII letters.
+type Realm = String    
+
+-- |Authorization credential to be sent by client with
+-- \"Authorization\" header. See
+-- 'Network.HTTP.Lucu.Resource.getAuthorization'.
+data AuthCredential
+    = BasicAuthCredential UserID Password
+      deriving (Show, Eq)
+
+-- |'UserID' is just a string which must not contain colon and any
+-- non-ASCII letters.
+type UserID   = String
+
+-- |'Password' is just a string which must not contain any non-ASCII
+-- letters.
+type Password = String
+
+
+instance Show AuthChallenge where
+    show (BasicAuthChallenge realm)
+        = "Basic realm=" ++ quoteStr realm
+
+
+authCredentialP :: Parser AuthCredential
+authCredentialP = allowEOF $!
+                  do string "Basic"
+                     many1 lws
+                     b64 <- many1
+                            $ satisfy (\ c -> (c >= 'a' && c <= 'z') ||
+                                              (c >= 'A' && c <= 'Z') ||
+                                              (c >= '0' && c <= '9') ||
+                                              c == '+' ||
+                                              c == '/' ||
+                                              c == '=')
+                     let decoded = map (toEnum . fromEnum) (B64.decode b64)
+                     case break (== ':') decoded of
+                       (uid, ':' : password)
+                           -> return (BasicAuthCredential uid password)
+                       _   -> failP
index a8d8011fdbb3b971b0aeb01b3edc6ac9efa5bbc0..12056ee8ec4fd2ac73fa9c8aac1682cdf1e88bd3 100644 (file)
@@ -85,6 +85,7 @@ module Network.HTTP.Lucu.Resource
     , getAcceptEncoding
     , isEncodingAcceptable
     , getContentType
+    , getAuthorization
 
     -- ** Finding an entity
 
@@ -117,6 +118,7 @@ module Network.HTTP.Lucu.Resource
     , setContentType
     , setLocation
     , setContentEncoding
+    , setWWWAuthenticate
 
     -- ** Writing a response body
 
@@ -143,6 +145,7 @@ import           Data.List
 import           Data.Maybe
 import           Data.Time
 import           Network.HTTP.Lucu.Abortion
+import           Network.HTTP.Lucu.Authorization
 import           Network.HTTP.Lucu.Config
 import           Network.HTTP.Lucu.ContentCoding
 import           Network.HTTP.Lucu.DefaultPage
@@ -365,6 +368,20 @@ getContentType
                                           (Just $ "Unparsable Content-Type: " ++ C8.unpack cType)
 
 
+-- |Get the header \"Authorization\" as
+-- 'Network.HTTP.Lucu.Authorization.AuthCredential'.
+getAuthorization :: Resource (Maybe AuthCredential)
+getAuthorization
+    = do authM <- getHeader (C8.pack "Authorization")
+         case authM of
+           Nothing
+               -> return Nothing
+           Just auth
+               -> case parse authCredentialP (L8.fromChunks [auth]) of
+                    (# Success a, _ #) -> return $ Just a
+                    (# _        , _ #) -> return Nothing
+
+
 {- ExaminingRequest 時に使用するアクション群 -}
 
 -- |Tell the system that the 'Resource' found an entity for the
@@ -806,6 +823,12 @@ setContentEncoding codings
                     _               -> undefined
          setHeader (C8.pack "Content-Encoding") (C8.pack $ joinWith ", " $ map tr codings)
 
+-- |Computation of @'setWWWAuthenticate' challenge@ sets the response
+-- header \"WWW-Authenticate\" to @challenge@.
+setWWWAuthenticate :: AuthChallenge -> Resource ()
+setWWWAuthenticate challenge
+    = setHeader (C8.pack "WWW-Authenticate") (C8.pack $ show challenge)
+
 
 {- DecidingBody 時に使用するアクション群 -}