diff --git a/source/Network/Xmpp.hs b/source/Network/Xmpp.hs index f545cba..cd1daf0 100644 --- a/source/Network/Xmpp.hs +++ b/source/Network/Xmpp.hs @@ -142,13 +142,10 @@ module Network.Xmpp , XmppFailure(..) , StreamErrorInfo(..) , StreamErrorCondition(..) - , AuthFailure( AuthXmlFailure -- Does not export AuthStreamFailure - , AuthNoAcceptableMechanism - , AuthChallengeFailure - , AuthNoStream - , AuthFailure + , AuthFailure( AuthNoAcceptableMechanism , AuthSaslFailure - , AuthStringPrepFailure ) + , AuthIllegalCredentials + , AuthOtherFailure ) ) where diff --git a/source/Network/Xmpp/Sasl.hs b/source/Network/Xmpp/Sasl.hs index fff8bb2..4d8a952 100644 --- a/source/Network/Xmpp/Sasl.hs +++ b/source/Network/Xmpp/Sasl.hs @@ -76,7 +76,7 @@ xmppSasl handlers stream = (flip withStream stream) $ do (_name, handler):_ -> do cs <- gets streamState case cs of - Closed -> return . Right $ Just AuthNoStream + Closed -> return . Left $ XmppNoStream _ -> lift $ handler stream -- | Authenticate to the server using the first matching method and bind a diff --git a/source/Network/Xmpp/Sasl/Common.hs b/source/Network/Xmpp/Sasl/Common.hs index eea0ce7..6a34aec 100644 --- a/source/Network/Xmpp/Sasl/Common.hs +++ b/source/Network/Xmpp/Sasl/Common.hs @@ -134,11 +134,11 @@ pullChallenge = do SaslChallenge (Just scb64) | Right sc <- B64.decode . Text.encodeUtf8 $ scb64 -> return $ Just sc - _ -> throwError AuthChallengeFailure + _ -> throwError AuthOtherFailure -- TODO: Log --- | Extract value from Just, failing with AuthChallengeFailure on Nothing. +-- | Extract value from Just, failing with AuthOtherFailure on Nothing. saslFromJust :: Maybe a -> ErrorT AuthFailure (StateT Stream IO) a -saslFromJust Nothing = throwError $ AuthChallengeFailure +saslFromJust Nothing = throwError $ AuthOtherFailure -- TODO: Log saslFromJust (Just d) = return d -- | Pull the next element and check that it is success. @@ -147,7 +147,7 @@ pullSuccess = do e <- pullSaslElement case e of SaslSuccess x -> return x - _ -> throwError $ AuthXmlFailure + _ -> throwError $ AuthOtherFailure -- TODO: Log -- | Pull the next element. When it's success, return it's payload. -- If it's a challenge, send an empty response and pull success. @@ -163,13 +163,13 @@ pullFinalMessage = do where decode Nothing = return Nothing decode (Just d) = case B64.decode $ Text.encodeUtf8 d of - Left _e -> throwError $ AuthChallengeFailure + Left _e -> throwError $ AuthOtherFailure -- TODO: Log Right x -> return $ Just x -- | Extract p=q pairs from a challenge. toPairs :: BS.ByteString -> ErrorT AuthFailure (StateT Stream IO) Pairs toPairs ctext = case pairs ctext of - Left _e -> throwError AuthChallengeFailure + Left _e -> throwError AuthOtherFailure -- TODO: Log Right r -> return r -- | Send a SASL response element. The content will be base64-encoded. @@ -186,7 +186,7 @@ respond m = do prepCredentials :: Text.Text -> Maybe Text.Text -> Text.Text -> ErrorT AuthFailure (StateT Stream IO) (Text.Text, Maybe Text.Text, Text.Text) prepCredentials authcid authzid password = case credentials of - Nothing -> throwError $ AuthStringPrepFailure + Nothing -> throwError $ AuthIllegalCredentials Just creds -> return creds where credentials = do diff --git a/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs b/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs index 809a95b..618ffb9 100644 --- a/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs +++ b/source/Network/Xmpp/Sasl/Mechanisms/Scram.hs @@ -63,7 +63,7 @@ scram hashToken authcid authzid password = do let (cfm, v) = cFinalMessageAndVerifier nonce salt ic sFirstMessage cnonce respond $ Just cfm finalPairs <- toPairs =<< saslFromJust =<< pullFinalMessage - unless (lookup "v" finalPairs == Just v) $ throwError AuthServerAuthFailure + unless (lookup "v" finalPairs == Just v) $ throwError AuthOtherFailure -- TODO: Log return () where -- We need to jump through some hoops to get a polymorphic solution @@ -106,7 +106,7 @@ scram hashToken authcid authzid password = do , Just ic <- lookup "i" pairs , [(i,"")] <- reads $ BS8.unpack ic = return (nonce, salt, i) - fromPairs _ _ = throwError $ AuthChallengeFailure + fromPairs _ _ = throwError $ AuthOtherFailure -- TODO: Log cFinalMessageAndVerifier :: BS.ByteString -> BS.ByteString diff --git a/source/Network/Xmpp/Sasl/Types.hs b/source/Network/Xmpp/Sasl/Types.hs index 8aea51e..fbdd408 100644 --- a/source/Network/Xmpp/Sasl/Types.hs +++ b/source/Network/Xmpp/Sasl/Types.hs @@ -8,22 +8,24 @@ import qualified Data.Text as Text import Network.Xmpp.Types import Control.Concurrent.STM -data AuthFailure = AuthXmlFailure - | AuthNoAcceptableMechanism [Text.Text] -- ^ Wraps mechanisms - -- offered - | AuthChallengeFailure - | AuthServerAuthFailure -- ^ The server failed to authenticate - -- itself - | AuthStreamFailure XmppFailure -- ^ Stream error on stream restart - -- TODO: Rename AuthConnectionFailure? - | AuthNoStream - | AuthFailure -- General instance used for the Error instance - | AuthSaslFailure SaslFailure -- ^ Defined SASL error condition - | AuthStringPrepFailure -- ^ StringPrep failed +-- | Signals a (non-fatal) SASL authentication error condition. +data AuthFailure = -- | No mechanism offered by the server was matched + -- by the provided acceptable mechanisms; wraps the + -- mechanisms offered by the server + AuthNoAcceptableMechanism [Text.Text] + | AuthStreamFailure XmppFailure -- TODO: Remove + -- | A SASL failure element was encountered + | AuthSaslFailure SaslFailure + -- | The credentials provided did not conform to + -- the SASLprep Stringprep profile + | AuthIllegalCredentials + -- | Other failure; more information is available + -- in the log + | AuthOtherFailure deriving Show instance Error AuthFailure where - noMsg = AuthFailure + noMsg = AuthOtherFailure data SaslElement = SaslSuccess (Maybe Text.Text) | SaslChallenge (Maybe Text.Text) diff --git a/source/Network/Xmpp/Types.hs b/source/Network/Xmpp/Types.hs index 5fd4f41..e2eae15 100644 --- a/source/Network/Xmpp/Types.hs +++ b/source/Network/Xmpp/Types.hs @@ -634,7 +634,7 @@ data StreamErrorInfo = StreamErrorInfo } deriving (Show, Eq) -- | Signals an XMPP stream error or another unpredicted stream-related --- situation. +-- situation. This error is fatal, and closes the XMPP stream. data XmppFailure = StreamErrorFailure StreamErrorInfo -- ^ An error XML stream -- element has been -- encountered. @@ -649,14 +649,19 @@ data XmppFailure = StreamErrorFailure StreamErrorInfo -- ^ An error XML stream -- constructor wraps the -- elements collected so -- far. - | TlsError TLS.TLSError - | TlsNoServerSupport - | XmppNoStream + | TlsError TLS.TLSError -- ^ An error occurred in the + -- TLS layer + | TlsNoServerSupport -- ^ The server does not support + -- the use of TLS + | XmppNoStream -- ^ An action that required an active + -- stream were performed when the + -- 'StreamState' was 'Closed' | TlsStreamSecured -- ^ Connection already secured | XmppOtherFailure -- ^ Undefined condition. More -- information should be available -- in the log. - | XmppIOException IOException + | XmppIOException IOException -- ^ An 'IOException' + -- occurred deriving (Show, Eq, Typeable) instance Exception XmppFailure