Browse Source

move mechanisms to Sasl/Mechanisms

factor out prepCredentials
master
Philipp Balzarek 14 years ago
parent
commit
3091a43914
  1. 6
      pontarius.cabal
  2. 33
      source/Network/Xmpp.hs
  3. 33
      source/Network/Xmpp/Sasl/Common.hs
  4. 9
      source/Network/Xmpp/Sasl/Mechanisms.hs
  5. 31
      source/Network/Xmpp/Sasl/Mechanisms/DigestMd5.hs
  6. 13
      source/Network/Xmpp/Sasl/Mechanisms/Plain.hs
  7. 28
      source/Network/Xmpp/Sasl/Mechanisms/Scram.hs

6
pontarius.cabal

@ -61,9 +61,9 @@ Library
, Network.Xmpp.Pickle , Network.Xmpp.Pickle
, Network.Xmpp.Presence , Network.Xmpp.Presence
, Network.Xmpp.Sasl , Network.Xmpp.Sasl
, Network.Xmpp.Sasl.Plain , Network.Xmpp.Sasl.Mechanisms.Plain
, Network.Xmpp.Sasl.DigestMd5 , Network.Xmpp.Sasl.Mechanisms.DigestMd5
, Network.Xmpp.Sasl.Scram , Network.Xmpp.Sasl.Mechanisms.Scram
, Network.Xmpp.Sasl.Types , Network.Xmpp.Sasl.Types
, Network.Xmpp.Session , Network.Xmpp.Session
, Network.Xmpp.Stream , Network.Xmpp.Stream

33
source/Network/Xmpp.hs

@ -146,26 +146,25 @@ module Network.Xmpp
, exampleParams , exampleParams
) where ) where
import Data.Text as Text import Data.Text as Text
import Network import Network
import qualified Network.TLS as TLS import qualified Network.TLS as TLS
import Network.Xmpp.Bind import Network.Xmpp.Bind
import Network.Xmpp.Concurrent import Network.Xmpp.Concurrent
import Network.Xmpp.Concurrent.Types import Network.Xmpp.Concurrent.Types
import Network.Xmpp.Message import Network.Xmpp.Message
import Network.Xmpp.Monad import Network.Xmpp.Monad
import Network.Xmpp.Presence import Network.Xmpp.Presence
import Network.Xmpp.Sasl import Network.Xmpp.Sasl
import Network.Xmpp.Sasl.Scram import Network.Xmpp.Sasl.Mechanisms
import Network.Xmpp.Sasl.Plain import Network.Xmpp.Sasl.Types
import Network.Xmpp.Sasl.Types import Network.Xmpp.Session
import Network.Xmpp.Session import Network.Xmpp.Stream
import Network.Xmpp.Stream import Network.Xmpp.TLS
import Network.Xmpp.TLS import Network.Xmpp.Types
import Network.Xmpp.Types
import Control.Monad.Error import Control.Monad.Error
-- | Connect to host with given address. -- | Connect to host with given address.
connect :: HostName -> Text -> XmppConMonad (Either StreamError ()) connect :: HostName -> Text -> XmppConMonad (Either StreamError ())

33
source/Network/Xmpp/Sasl/Common.hs

@ -10,19 +10,21 @@ import Control.Monad.Error
import Control.Monad.State.Class import Control.Monad.State.Class
import qualified Data.Attoparsec.ByteString.Char8 as AP import qualified Data.Attoparsec.ByteString.Char8 as AP
import Data.Bits
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Base64 as B64 import qualified Data.ByteString.Base64 as B64
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Maybe (maybeToList) import Data.Maybe (maybeToList)
import qualified Data.Text as Text import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text import qualified Data.Text.Encoding as Text
import Data.Word (Word8)
import Data.XML.Pickle import Data.XML.Pickle
import Data.XML.Types import Data.XML.Types
import Data.Word (Word8)
import Network.Xmpp.Monad import Network.Xmpp.Monad
import Network.Xmpp.Pickle import Network.Xmpp.Pickle
import Network.Xmpp.Sasl.Types import Network.Xmpp.Sasl.Types
import Network.Xmpp.Sasl.StringPrep
import qualified System.Random as Random import qualified System.Random as Random
@ -166,3 +168,32 @@ toPairs ctext = case pairs ctext of
respond :: Maybe BS.ByteString -> SaslM Bool respond :: Maybe BS.ByteString -> SaslM Bool
respond = lift . pushElement . saslResponseE . respond = lift . pushElement . saslResponseE .
fmap (Text.decodeUtf8 . B64.encode) fmap (Text.decodeUtf8 . B64.encode)
-- | Run the appropriate stringprep profiles on the credentials.
-- May fail Fails with 'AuthStringPrepError'
prepCredentials :: Text.Text -> Maybe Text.Text -> Text.Text
-> SaslM (Text.Text, Maybe Text.Text, Text.Text)
prepCredentials authcid authzid password = case credentials of
Nothing -> throwError $ AuthStringPrepError
Just (ac, az, pw) -> return (ac, az, pw)
where
credentials = do
ac <- normalizeUsername authcid
az <- case authzid of
Nothing -> Just Nothing
Just az' -> Just <$> normalizeUsername az'
pw <- normalizePassword password
return (ac, az, pw)
-- | Bit-wise xor of byte strings
xorBS :: BS.ByteString -> BS.ByteString -> BS.ByteString
xorBS x y = BS.pack $ BS.zipWith xor x y
-- | Join byte strings with ","
merge :: [BS.ByteString] -> BS.ByteString
merge = BS.intercalate ","
-- | Infix concatenation of byte strings
(+++) :: BS.ByteString -> BS.ByteString -> BS.ByteString
(+++) = BS.append

9
source/Network/Xmpp/Sasl/Mechanisms.hs

@ -0,0 +1,9 @@
module Network.Xmpp.Sasl.Mechanisms
( module Network.Xmpp.Sasl.Mechanisms.DigestMd5
, module Network.Xmpp.Sasl.Mechanisms.Scram
, module Network.Xmpp.Sasl.Mechanisms.Plain
) where
import Network.Xmpp.Sasl.Mechanisms.DigestMd5
import Network.Xmpp.Sasl.Mechanisms.Scram
import Network.Xmpp.Sasl.Mechanisms.Plain

31
source/Network/Xmpp/Sasl/DigestMd5.hs → source/Network/Xmpp/Sasl/Mechanisms/DigestMd5.hs

@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Network.Xmpp.Sasl.DigestMd5 where module Network.Xmpp.Sasl.Mechanisms.DigestMd5 where
import Control.Applicative import Control.Applicative
import Control.Arrow (left) import Control.Arrow (left)
@ -40,27 +40,18 @@ import Network.Xmpp.Sasl.Types
xmppDigestMd5 :: Maybe Text -- Authorization identity (authzid) xmppDigestMd5 :: Text -- Authorization identity (authzid)
-> Text -- Authentication identity (authzid) -> Maybe Text -- Authentication identity (authzid)
-> Text -- Password (authzid) -> Text -- Password (authzid)
-> SaslM () -> SaslM ()
xmppDigestMd5 authzid authcid password = do xmppDigestMd5 authcid authzid password = do
case credentials of (ac, az, pw) <- prepCredentials authcid authzid password
Nothing -> throwError $ AuthStringPrepError hn <- gets sHostname
Just (ac, az, pw) -> do case hn of
hn <- gets sHostname Just hn' -> do
case hn of xmppDigestMd5' hn' ac az pw
Just hn' -> do Nothing -> throwError AuthConnectionError
xmppDigestMd5' hn' ac az pw
Nothing -> throwError AuthConnectionError
where where
credentials = do
ac <- normalizeUsername authcid
az <- case authzid of
Nothing -> Just Nothing
Just az' -> Just <$> normalizeUsername az'
pw <- normalizePassword password
return (ac, az, pw)
xmppDigestMd5' :: Text -> Text -> Maybe Text -> Text -> SaslM () xmppDigestMd5' :: Text -> Text -> Maybe Text -> Text -> SaslM ()
xmppDigestMd5' hostname authcid authzid password = do xmppDigestMd5' hostname authcid authzid password = do
-- Push element and receive the challenge (in SaslM). -- Push element and receive the challenge (in SaslM).
@ -142,5 +133,5 @@ digestMd5 :: Maybe Text -- Authorization identity (authzid)
-> Text -- Password (authzid) -> Text -- Password (authzid)
-> SaslHandler -> SaslHandler
digestMd5 authzid authcid password = ( "DIGEST-MD5" digestMd5 authzid authcid password = ( "DIGEST-MD5"
, xmppDigestMd5 authzid authcid password , xmppDigestMd5 authcid authzid password
) )

13
source/Network/Xmpp/Sasl/Plain.hs → source/Network/Xmpp/Sasl/Mechanisms/Plain.hs

@ -3,7 +3,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Network.Xmpp.Sasl.Plain where module Network.Xmpp.Sasl.Mechanisms.Plain where
import Control.Applicative import Control.Applicative
import Control.Arrow (left) import Control.Arrow (left)
@ -50,18 +50,19 @@ xmppPlain :: Text.Text -- ^ Password
-> Maybe Text.Text -- ^ Authorization identity (authzid) -> Maybe Text.Text -- ^ Authorization identity (authzid)
-> Text.Text -- ^ Authentication identity (authcid) -> Text.Text -- ^ Authentication identity (authcid)
-> SaslM () -> SaslM ()
xmppPlain authcid authzid passwd = do xmppPlain authcid authzid password = do
_ <- saslInit "PLAIN" ( Just $ plainMessage authzid authcid passwd) (ac, az, pw) <- prepCredentials authcid authzid password
_ <- saslInit "PLAIN" ( Just $ plainMessage ac az pw)
_ <- pullSuccess _ <- pullSuccess
return () return ()
where where
-- Converts an optional authorization identity, an authentication identity, -- Converts an optional authorization identity, an authentication identity,
-- and a password to a \NUL-separated PLAIN message. -- and a password to a \NUL-separated PLAIN message.
plainMessage :: Maybe Text.Text -- Authorization identity (authzid) plainMessage :: Text.Text -- Authorization identity (authzid)
-> Text.Text -- Authentication identity (authcid) -> Maybe Text.Text -- Authentication identity (authcid)
-> Text.Text -- Password -> Text.Text -- Password
-> BS.ByteString -- The PLAIN message -> BS.ByteString -- The PLAIN message
plainMessage authzid authcid passwd = BS.concat $ plainMessage authcid authzid passwd = BS.concat $
[ authzid' [ authzid'
, "\NUL" , "\NUL"
, Text.encodeUtf8 $ authcid , Text.encodeUtf8 $ authcid

28
source/Network/Xmpp/Sasl/Scram.hs → source/Network/Xmpp/Sasl/Mechanisms/Scram.hs

@ -2,7 +2,7 @@
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Network.Xmpp.Sasl.Scram where module Network.Xmpp.Sasl.Mechanisms.Scram where
import Control.Applicative ((<$>)) import Control.Applicative ((<$>))
import Control.Monad.Error import Control.Monad.Error
@ -11,7 +11,6 @@ import qualified Crypto.Classes as Crypto
import qualified Crypto.HMAC as Crypto import qualified Crypto.HMAC as Crypto
import qualified Crypto.Hash.SHA1 as Crypto import qualified Crypto.Hash.SHA1 as Crypto
import Data.Binary(Binary,encode) import Data.Binary(Binary,encode)
import Data.Bits
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Base64 as B64 import qualified Data.ByteString.Base64 as B64
import Data.ByteString.Char8 as BS8 (unpack) import Data.ByteString.Char8 as BS8 (unpack)
@ -29,18 +28,6 @@ import Network.Xmpp.Sasl.Common
import Network.Xmpp.Sasl.StringPrep import Network.Xmpp.Sasl.StringPrep
import Network.Xmpp.Sasl.Types import Network.Xmpp.Sasl.Types
-- | Bit-wise xor of byte strings
xorBS :: BS.ByteString -> BS.ByteString -> BS.ByteString
xorBS x y = BS.pack $ BS.zipWith xor x y
-- | Join byte strings with ","
merge :: [BS.ByteString] -> BS.ByteString
merge = BS.intercalate ","
-- | Infix concatenation of byte strings
(+++) :: BS.ByteString -> BS.ByteString -> BS.ByteString
(+++) = BS.append
-- | A nicer name for undefined, for use as a dummy token to determin -- | A nicer name for undefined, for use as a dummy token to determin
-- the hash function to use -- the hash function to use
hashToken :: (Crypto.Hash ctx hash) => hash hashToken :: (Crypto.Hash ctx hash) => hash
@ -57,17 +44,10 @@ scram :: (Crypto.Hash ctx hash)
-> Maybe Text.Text -- ^ Authorization ID -> Maybe Text.Text -- ^ Authorization ID
-> Text.Text -- ^ Password -> Text.Text -- ^ Password
-> SaslM () -> SaslM ()
scram hashToken authcid authzid password = case credentials of scram hashToken authcid authzid password = do
Nothing -> throwError $ AuthStringPrepError (ac, az, pw) <- prepCredentials authcid authzid password
Just (ac, az, pw) -> scramhelper hashToken ac az pw scramhelper hashToken ac az pw
where where
credentials = do
ac <- normalizeUsername authcid
az <- case authzid of
Nothing -> Just Nothing
Just az' -> Just <$> normalizeUsername az'
pw <- normalizePassword password
return (ac, az, pw)
scramhelper hashToken authcid authzid' password = do scramhelper hashToken authcid authzid' password = do
cnonce <- liftIO $ makeNonce cnonce <- liftIO $ makeNonce
saslInit "SCRAM-SHA-1" (Just $ cFirstMessage cnonce) saslInit "SCRAM-SHA-1" (Just $ cFirstMessage cnonce)
Loading…
Cancel
Save