Make maintenance logins resilient to LDAP failures
This commit is contained in:
parent
99354919ba
commit
b4f08c28df
@ -87,6 +87,7 @@ dependencies:
|
||||
- gitrev
|
||||
- Glob
|
||||
- ldap-client
|
||||
- connection
|
||||
|
||||
# The library contains all of our application code. The executable
|
||||
# defined below is just a thin wrapper.
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
module Auth.LDAP
|
||||
( campusLogin
|
||||
, CampusUserException(..)
|
||||
, campusUser
|
||||
, CampusMessage(..)
|
||||
, Ldap.AttrList, Ldap.Attr(..), Ldap.AttrValue
|
||||
@ -17,6 +18,9 @@ module Auth.LDAP
|
||||
|
||||
import Import.NoFoundation
|
||||
import Control.Lens
|
||||
import Network.Connection
|
||||
|
||||
import qualified Control.Monad.Catch as Exc
|
||||
|
||||
import Utils.Form
|
||||
|
||||
@ -108,6 +112,9 @@ campusLogin conf@LdapConf{..} = AuthPlugin{..}
|
||||
$(widgetFile "widgets/campus-login-form")
|
||||
|
||||
data CampusUserException = CampusUserLdapError Ldap.LdapError
|
||||
| CampusUserHostNotResolved String
|
||||
| CampusUserLineTooLong
|
||||
| CampusUserHostCannotConnect String [IOException]
|
||||
| CampusUserNoResult
|
||||
| CampusUserAmbiguous
|
||||
deriving (Show, Eq, Typeable)
|
||||
@ -115,7 +122,7 @@ data CampusUserException = CampusUserLdapError Ldap.LdapError
|
||||
instance Exception CampusUserException
|
||||
|
||||
campusUser :: (MonadIO m, MonadThrow m) => LdapConf -> Creds site -> m (Ldap.AttrList [])
|
||||
campusUser conf@LdapConf{..} Creds{..} = liftIO $ either (throwM . CampusUserLdapError) return <=< Ldap.with ldapHost ldapPort $ \ldap -> do
|
||||
campusUser conf@LdapConf{..} Creds{..} = liftIO . (`catches` errHandlers) $ either (throwM . CampusUserLdapError) return <=< Ldap.with ldapHost ldapPort $ \ldap -> do
|
||||
Ldap.bind ldap ldapDn ldapPassword
|
||||
results <- case lookup "DN" credsExtra of
|
||||
Just userDN -> do
|
||||
@ -133,6 +140,11 @@ campusUser conf@LdapConf{..} Creds{..} = liftIO $ either (throwM . CampusUserLda
|
||||
[] -> throwM CampusUserNoResult
|
||||
[Ldap.SearchEntry _ attrs] -> return attrs
|
||||
_otherwise -> throwM CampusUserAmbiguous
|
||||
where
|
||||
errHandlers = [ Exc.Handler $ \LineTooLong -> throwM CampusUserLineTooLong
|
||||
, Exc.Handler $ \(HostNotResolved host) -> throwM $ CampusUserHostNotResolved host
|
||||
, Exc.Handler $ \(HostCannotConnect host excs) -> throwM $ CampusUserHostCannotConnect host excs
|
||||
]
|
||||
|
||||
-- ldapConfig :: UniWorX -> LDAPConfig
|
||||
-- ldapConfig _app@(appSettings -> settings) = LDAPConfig
|
||||
|
||||
@ -70,6 +70,7 @@ import Control.Monad.Trans.Reader (runReader)
|
||||
import Control.Monad.Trans.Writer (WriterT(..))
|
||||
import Control.Monad.Writer.Class (MonadWriter(..))
|
||||
import Control.Monad.Catch (handleAll)
|
||||
import qualified Control.Monad.Catch as C
|
||||
|
||||
import System.FilePath
|
||||
|
||||
@ -1076,23 +1077,45 @@ instance YesodAuth UniWorX where
|
||||
setTitleI MsgLoginTitle
|
||||
$(widgetFile "login")
|
||||
|
||||
authenticate creds@(Creds{..}) = runDB . fmap (either id id) . runExceptT $ do
|
||||
let (userPlugin, userIdent)
|
||||
| isDummy
|
||||
, [dummyPlugin, dummyIdent] <- Text.splitOn ":" credsIdent
|
||||
= (dummyPlugin, dummyIdent)
|
||||
| otherwise
|
||||
= (credsPlugin, credsIdent)
|
||||
isDummy = credsPlugin == "dummy"
|
||||
isPWFile = credsPlugin == "PWFile"
|
||||
uAuth = UniqueAuthentication userPlugin userIdent
|
||||
authenticate Creds{..} = runDB $ do
|
||||
let
|
||||
(userPlugin, userIdent)
|
||||
| isDummy
|
||||
, [dummyPlugin, dummyIdent] <- Text.splitOn ":" credsIdent
|
||||
= (dummyPlugin, dummyIdent)
|
||||
| otherwise
|
||||
= (credsPlugin, credsIdent)
|
||||
isDummy = credsPlugin == "dummy"
|
||||
isPWFile = credsPlugin == "PWFile"
|
||||
uAuth = UniqueAuthentication userPlugin userIdent
|
||||
|
||||
$logDebugS "auth" $ tshow creds
|
||||
excHandlers
|
||||
| isDummy || isPWFile
|
||||
= [ C.Handler $ \err -> do
|
||||
addMessage "error" (toHtml $ tshow (err :: CampusUserException))
|
||||
$logErrorS "LDAP" $ tshow err
|
||||
acceptExisting
|
||||
]
|
||||
| otherwise
|
||||
= [ C.Handler $ \case
|
||||
CampusUserNoResult -> do
|
||||
$logWarnS "LDAP" $ "User lookup failed after successful login for " <> credsIdent
|
||||
return . UserError $ IdentifierNotFound credsIdent
|
||||
CampusUserAmbiguous -> do
|
||||
$logWarnS "LDAP" $ "Multiple LDAP results for " <> credsIdent
|
||||
return . UserError $ IdentifierNotFound credsIdent
|
||||
err -> do
|
||||
$logErrorS "LDAP" $ tshow err
|
||||
return $ ServerError "LDAP lookup failed"
|
||||
]
|
||||
|
||||
acceptExisting = maybe (UserError $ IdentifierNotFound credsIdent) (Authenticated . entityKey) <$> getBy uAuth
|
||||
|
||||
$logDebugS "auth" $ tshow Creds{..}
|
||||
AppSettings{..} <- getsYesod appSettings
|
||||
|
||||
case appLdapConf of
|
||||
Just ldapConf -> do
|
||||
flip catches excHandlers $ case appLdapConf of
|
||||
Just ldapConf -> fmap (either id id) . runExceptT $ do
|
||||
ldapData <- campusUser ldapConf $ Creds userPlugin userIdent credsExtra
|
||||
$logDebugS "LDAP" $ "Successful LDAP lookup: " <> tshow ldapData
|
||||
|
||||
@ -1155,8 +1178,7 @@ instance YesodAuth UniWorX where
|
||||
|
||||
lift $ insertMany_ fs
|
||||
return $ Authenticated userId
|
||||
Nothing -> (throwError =<<) . lift $
|
||||
maybe (UserError $ IdentifierNotFound credsIdent) (Authenticated . entityKey) <$> getBy uAuth
|
||||
Nothing -> acceptExisting
|
||||
|
||||
where
|
||||
insertMaybe key val = get key >>= maybe (insert_ val) (\_ -> return ())
|
||||
|
||||
Loading…
Reference in New Issue
Block a user