Introduce timeouts for all ldap actions
This commit is contained in:
parent
b938981d0e
commit
0a69047acf
@ -66,7 +66,8 @@ ldap:
|
|||||||
pass: "_env:LDAPPASS:"
|
pass: "_env:LDAPPASS:"
|
||||||
baseDN: "_env:LDAPBASE:"
|
baseDN: "_env:LDAPBASE:"
|
||||||
scope: "_env:LDAPSCOPE:WholeSubtree"
|
scope: "_env:LDAPSCOPE:WholeSubtree"
|
||||||
timeout: "_env:LDAPSEARCHTIME:5"
|
timeout: "_env:LDAPTIMEOUT:5"
|
||||||
|
search-timeout: "_env:LDAPSEARCHTIME:5"
|
||||||
pool:
|
pool:
|
||||||
stripes: "_env:LDAPSTRIPES:1"
|
stripes: "_env:LDAPSTRIPES:1"
|
||||||
timeout: "_env:LDAPTIMEOUT:20"
|
timeout: "_env:LDAPTIMEOUT:20"
|
||||||
|
|||||||
@ -113,6 +113,7 @@ dependencies:
|
|||||||
- pkcs7
|
- pkcs7
|
||||||
- memcached-binary
|
- memcached-binary
|
||||||
- directory-tree
|
- directory-tree
|
||||||
|
- lifted-base
|
||||||
|
|
||||||
other-extensions:
|
other-extensions:
|
||||||
- GeneralizedNewtypeDeriving
|
- GeneralizedNewtypeDeriving
|
||||||
|
|||||||
@ -168,7 +168,7 @@ makeFoundation appSettings@AppSettings{..} = do
|
|||||||
(pgConnStr appDatabaseConf)
|
(pgConnStr appDatabaseConf)
|
||||||
(pgPoolSize appDatabaseConf)
|
(pgPoolSize appDatabaseConf)
|
||||||
|
|
||||||
ldapPool <- for appLdapConf $ \LdapConf{..} -> createLdapPool ldapHost ldapPort (poolStripes ldapPool) (poolTimeout ldapPool) (poolLimit ldapPool)
|
ldapPool <- for appLdapConf $ \LdapConf{..} -> createLdapPool ldapHost ldapPort (poolStripes ldapPool) (poolTimeout ldapPool) ldapTimeout (poolLimit ldapPool)
|
||||||
|
|
||||||
-- Perform database migration using our application's logging settings.
|
-- Perform database migration using our application's logging settings.
|
||||||
migrateAll `runSqlPool` sqlPool
|
migrateAll `runSqlPool` sqlPool
|
||||||
|
|||||||
@ -44,7 +44,7 @@ findUser LdapConf{..} ldap campusIdent = Ldap.search ldap ldapBase userSearchSet
|
|||||||
userSearchSettings = mconcat
|
userSearchSettings = mconcat
|
||||||
[ Ldap.scope ldapScope
|
[ Ldap.scope ldapScope
|
||||||
, Ldap.size 2
|
, Ldap.size 2
|
||||||
, Ldap.time ldapTimeout
|
, Ldap.time ldapSearchTimeout
|
||||||
, Ldap.derefAliases Ldap.DerefAlways
|
, Ldap.derefAliases Ldap.DerefAlways
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ campusLogin conf@LdapConf{..} pool = AuthPlugin{..}
|
|||||||
findUser conf ldap campusIdent [userPrincipalName]
|
findUser conf ldap campusIdent [userPrincipalName]
|
||||||
case ldapResult of
|
case ldapResult of
|
||||||
Left err
|
Left err
|
||||||
| Ldap.ResponseError (Ldap.ResponseErrorCode _ Ldap.InvalidCredentials _ _) <- err
|
| LdapError (Ldap.ResponseError (Ldap.ResponseErrorCode _ Ldap.InvalidCredentials _ _)) <- err
|
||||||
-> do
|
-> do
|
||||||
$logDebugS "LDAP" "Invalid credentials"
|
$logDebugS "LDAP" "Invalid credentials"
|
||||||
loginErrorMessageI LoginR Msg.InvalidLogin
|
loginErrorMessageI LoginR Msg.InvalidLogin
|
||||||
@ -110,7 +110,7 @@ campusLogin conf@LdapConf{..} pool = AuthPlugin{..}
|
|||||||
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderAForm FormStandard campusForm
|
(login, loginEnctype) <- handlerToWidget . generateFormPost $ renderAForm FormStandard campusForm
|
||||||
$(widgetFile "widgets/campus-login-form")
|
$(widgetFile "widgets/campus-login-form")
|
||||||
|
|
||||||
data CampusUserException = CampusUserLdapError Ldap.LdapError
|
data CampusUserException = CampusUserLdapError LdapPoolError
|
||||||
| CampusUserHostNotResolved String
|
| CampusUserHostNotResolved String
|
||||||
| CampusUserLineTooLong
|
| CampusUserLineTooLong
|
||||||
| CampusUserHostCannotConnect String [IOException]
|
| CampusUserHostCannotConnect String [IOException]
|
||||||
@ -129,7 +129,7 @@ campusUser conf@LdapConf{..} pool Creds{..} = liftIO . (`catches` errHandlers) $
|
|||||||
userSearchSettings = mconcat
|
userSearchSettings = mconcat
|
||||||
[ Ldap.scope Ldap.BaseObject
|
[ Ldap.scope Ldap.BaseObject
|
||||||
, Ldap.size 2
|
, Ldap.size 2
|
||||||
, Ldap.time ldapTimeout
|
, Ldap.time ldapSearchTimeout
|
||||||
, Ldap.derefAliases Ldap.DerefAlways
|
, Ldap.derefAliases Ldap.DerefAlways
|
||||||
]
|
]
|
||||||
Ldap.search ldap (Ldap.Dn userDN) userSearchSettings userFilter []
|
Ldap.search ldap (Ldap.Dn userDN) userSearchSettings userFilter []
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
module Ldap.Client.Pool
|
module Ldap.Client.Pool
|
||||||
( LdapPool
|
( LdapPool
|
||||||
, LdapExecutor, Ldap, LdapError
|
, LdapExecutor, Ldap, LdapError
|
||||||
|
, LdapPoolError(..)
|
||||||
, withLdap
|
, withLdap
|
||||||
, createLdapPool
|
, createLdapPool
|
||||||
) where
|
) where
|
||||||
@ -19,17 +20,24 @@ import Data.Time.Clock (NominalDiffTime)
|
|||||||
|
|
||||||
import Data.Dynamic
|
import Data.Dynamic
|
||||||
|
|
||||||
|
import System.Timeout.Lifted
|
||||||
|
|
||||||
|
|
||||||
type LdapPool = Pool LdapExecutor
|
type LdapPool = Pool LdapExecutor
|
||||||
data LdapExecutor = LdapExecutor
|
data LdapExecutor = LdapExecutor
|
||||||
{ ldapExec :: forall a. Typeable a => (Ldap -> IO a) -> IO (Either LdapError a)
|
{ ldapExec :: forall a. Typeable a => (Ldap -> IO a) -> IO (Either LdapPoolError a)
|
||||||
, ldapDestroy :: TMVar ()
|
, ldapDestroy :: TMVar ()
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Exception LdapError
|
instance Exception LdapError
|
||||||
|
|
||||||
|
data LdapPoolError = LdapPoolTimeout | LdapError LdapError
|
||||||
|
deriving (Eq, Show, Generic, Typeable)
|
||||||
|
|
||||||
withLdap :: (MonadBaseControl IO m, MonadIO m, Typeable a) => LdapPool -> (Ldap -> IO a) -> m (Either LdapError a)
|
instance Exception LdapPoolError
|
||||||
|
|
||||||
|
|
||||||
|
withLdap :: (MonadBaseControl IO m, MonadIO m, Typeable a) => LdapPool -> (Ldap -> IO a) -> m (Either LdapPoolError a)
|
||||||
withLdap pool act = withResource pool $ \LdapExecutor{..} -> liftIO $ ldapExec act
|
withLdap pool act = withResource pool $ \LdapExecutor{..} -> liftIO $ ldapExec act
|
||||||
|
|
||||||
|
|
||||||
@ -37,10 +45,11 @@ createLdapPool :: ( MonadLoggerIO m, MonadIO m )
|
|||||||
=> Ldap.Host
|
=> Ldap.Host
|
||||||
-> Ldap.PortNumber
|
-> Ldap.PortNumber
|
||||||
-> Int -- ^ Stripes
|
-> Int -- ^ Stripes
|
||||||
-> NominalDiffTime -- ^ Timeout
|
-> NominalDiffTime -- ^ Connection Timeout
|
||||||
|
-> NominalDiffTime -- ^ Action Timeout
|
||||||
-> Int -- ^ Limit
|
-> Int -- ^ Limit
|
||||||
-> m LdapPool
|
-> m LdapPool
|
||||||
createLdapPool host port stripes timeout limit = do
|
createLdapPool host port stripes timeoutConn (round . (* 1e6) -> timeoutAct) limit = do
|
||||||
logFunc <- askLoggerIO
|
logFunc <- askLoggerIO
|
||||||
|
|
||||||
let
|
let
|
||||||
@ -50,16 +59,17 @@ createLdapPool host port stripes timeout limit = do
|
|||||||
ldapAct <- newEmptyTMVarIO
|
ldapAct <- newEmptyTMVarIO
|
||||||
|
|
||||||
let
|
let
|
||||||
ldapExec :: forall a. Typeable a => (Ldap -> IO a) -> IO (Either LdapError a)
|
ldapExec :: forall a. Typeable a => (Ldap -> IO a) -> IO (Either LdapPoolError a)
|
||||||
ldapExec act = do
|
ldapExec act = do
|
||||||
ldapAnswer <- newEmptyTMVarIO :: IO (TMVar (Either SomeException Dynamic))
|
ldapAnswer <- newEmptyTMVarIO :: IO (TMVar (Either SomeException Dynamic))
|
||||||
atomically $ putTMVar ldapAct (fmap toDyn . act, ldapAnswer)
|
atomically $ putTMVar ldapAct (fmap toDyn . act, ldapAnswer)
|
||||||
either throwIO (return . Right . flip fromDyn (error "Could not cast dynamic")) =<< atomically (takeTMVar ldapAnswer)
|
either throwIO (return . Right . flip fromDyn (error "Could not cast dynamic")) =<< atomically (takeTMVar ldapAnswer)
|
||||||
`catches`
|
`catches`
|
||||||
[ Handler $ return . Left . Ldap.ParseError
|
[ Handler $ return . Left . LdapError . Ldap.ParseError
|
||||||
, Handler $ return . Left . Ldap.ResponseError
|
, Handler $ return . Left . LdapError . Ldap.ResponseError
|
||||||
, Handler $ return . Left . Ldap.IOError
|
, Handler $ return . Left . LdapError . Ldap.IOError
|
||||||
, Handler $ return . Left . Ldap.DisconnectError
|
, Handler $ return . Left . LdapError . Ldap.DisconnectError
|
||||||
|
, Handler $ return . Left . (id :: LdapPoolError -> LdapPoolError)
|
||||||
]
|
]
|
||||||
|
|
||||||
go :: Maybe (TMVar (Maybe a)) -> Ldap -> LoggingT IO ()
|
go :: Maybe (TMVar (Maybe a)) -> Ldap -> LoggingT IO ()
|
||||||
@ -71,7 +81,7 @@ createLdapPool host port stripes timeout limit = do
|
|||||||
Nothing -> $logDebugS "LdapExecutor" "Terminating"
|
Nothing -> $logDebugS "LdapExecutor" "Terminating"
|
||||||
Just (act, returnRes) -> do
|
Just (act, returnRes) -> do
|
||||||
$logDebugS "LdapExecutor" "Executing"
|
$logDebugS "LdapExecutor" "Executing"
|
||||||
res <- try . liftIO $ act ldap
|
res <- try . withTimeout . liftIO $ act ldap
|
||||||
didReturn <- atomically $ tryPutTMVar returnRes res
|
didReturn <- atomically $ tryPutTMVar returnRes res
|
||||||
unless didReturn $
|
unless didReturn $
|
||||||
$logErrorS "LdapExecutor" "Could not return result"
|
$logErrorS "LdapExecutor" "Could not return result"
|
||||||
@ -81,20 +91,25 @@ createLdapPool host port stripes timeout limit = do
|
|||||||
]
|
]
|
||||||
go Nothing ldap
|
go Nothing ldap
|
||||||
|
|
||||||
setup <- newEmptyTMVarIO
|
withTimeout $ do
|
||||||
void . fork . flip runLoggingT logFunc $ do
|
setup <- newEmptyTMVarIO
|
||||||
$logDebugS "LdapExecutor" "Starting"
|
|
||||||
res <- liftIO . Ldap.with host port $ flip runLoggingT logFunc . go (Just setup)
|
|
||||||
case res of
|
|
||||||
Left exc -> do
|
|
||||||
$logWarnS "LdapExecutor" $ tshow exc
|
|
||||||
atomically . void . tryPutTMVar setup $ Just exc
|
|
||||||
Right res' -> return res'
|
|
||||||
|
|
||||||
maybe (return ()) throwM =<< atomically (takeTMVar setup)
|
void . fork . flip runLoggingT logFunc $ do
|
||||||
|
$logDebugS "LdapExecutor" "Starting"
|
||||||
|
res <- liftIO . Ldap.with host port $ flip runLoggingT logFunc . go (Just setup)
|
||||||
|
case res of
|
||||||
|
Left exc -> do
|
||||||
|
$logWarnS "LdapExecutor" $ tshow exc
|
||||||
|
atomically . void . tryPutTMVar setup $ Just exc
|
||||||
|
Right res' -> return res'
|
||||||
|
|
||||||
|
maybe (return ()) throwM =<< atomically (takeTMVar setup)
|
||||||
|
|
||||||
return LdapExecutor{..}
|
return LdapExecutor{..}
|
||||||
|
|
||||||
delExecutor :: LdapExecutor -> IO ()
|
delExecutor :: LdapExecutor -> IO ()
|
||||||
delExecutor LdapExecutor{..} = atomically . void $ tryPutTMVar ldapDestroy ()
|
delExecutor LdapExecutor{..} = atomically . void $ tryPutTMVar ldapDestroy ()
|
||||||
liftIO $ createPool mkExecutor delExecutor stripes timeout limit
|
liftIO $ createPool mkExecutor delExecutor stripes timeoutConn limit
|
||||||
|
where
|
||||||
|
withTimeout :: forall m a. (MonadBaseControl IO m, MonadThrow m) => m a -> m a
|
||||||
|
withTimeout = maybe (throwM LdapPoolTimeout) return <=< timeout timeoutAct
|
||||||
|
|||||||
@ -165,7 +165,8 @@ data LdapConf = LdapConf
|
|||||||
, ldapDn :: Ldap.Dn, ldapPassword :: Ldap.Password
|
, ldapDn :: Ldap.Dn, ldapPassword :: Ldap.Password
|
||||||
, ldapBase :: Ldap.Dn
|
, ldapBase :: Ldap.Dn
|
||||||
, ldapScope :: Ldap.Scope
|
, ldapScope :: Ldap.Scope
|
||||||
, ldapTimeout :: Int32
|
, ldapTimeout :: NominalDiffTime
|
||||||
|
, ldapSearchTimeout :: Int32
|
||||||
, ldapPool :: ResourcePoolConf
|
, ldapPool :: ResourcePoolConf
|
||||||
} deriving (Show)
|
} deriving (Show)
|
||||||
|
|
||||||
@ -253,6 +254,7 @@ instance FromJSON LdapConf where
|
|||||||
ldapBase <- Ldap.Dn <$> o .: "baseDN"
|
ldapBase <- Ldap.Dn <$> o .: "baseDN"
|
||||||
ldapScope <- o .: "scope"
|
ldapScope <- o .: "scope"
|
||||||
ldapTimeout <- o .: "timeout"
|
ldapTimeout <- o .: "timeout"
|
||||||
|
ldapSearchTimeout <- o .: "search-timeout"
|
||||||
ldapPool <- o .: "pool"
|
ldapPool <- o .: "pool"
|
||||||
return LdapConf{..}
|
return LdapConf{..}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user