fix(ldap): allow ldap update for mangled user entries

This commit is contained in:
Steffen Jost 2023-02-07 18:31:13 +01:00
parent 6098d4554d
commit 006ab632a3
4 changed files with 34 additions and 10 deletions

View File

@ -174,7 +174,7 @@ upsertCampusUserByCn persNo = upsertCampusUser UpsertCampusUserGuessUser [(ldapP
-- | Upsert User DB according to given LDAP data (does not query LDAP itself) -- | Upsert User DB according to given LDAP data (does not query LDAP itself)
upsertCampusUser :: forall m. upsertCampusUser :: forall m.
( MonadHandler m, HandlerSite m ~ UniWorX ( MonadHandler m, HandlerSite m ~ UniWorX
, MonadThrow m , MonadCatch m
) )
=> UpsertCampusUserMode -> Ldap.AttrList [] -> SqlPersistT m (Entity User) => UpsertCampusUserMode -> Ldap.AttrList [] -> SqlPersistT m (Entity User)
upsertCampusUser upsertMode ldapData = do upsertCampusUser upsertMode ldapData = do
@ -193,7 +193,14 @@ upsertCampusUser upsertMode ldapData = do
(newUser ^. _userFirstName) (newUser ^. _userFirstName)
(newUser ^. _userSurname) (newUser ^. _userSurname)
(userRec ^. _userDisplayName)) $ (userRec ^. _userDisplayName)) $
update userId [ UserDisplayName =. (newUser ^. _userDisplayName) ] update userId [ UserDisplayName =. (newUser ^. _userDisplayName) ]
when (validEmail' (userRec ^. _userEmail)) $ do
let emUps = [ UserDisplayEmail =. (newUser ^. _userEmail) | not (validEmail' (userRec ^. _userDisplayEmail)) ]
++ [ UserAuthentication =. AuthLDAP | is _AuthNoLogin (userRec ^. _userAuthentication) ]
unless (null emUps) $ update userId emUps
-- Attempt to update ident, too:
unless (validEmail' (userRec ^. _userIdent)) $
void $ maybeCatchAll (update userId [ UserIdent =. (newUser ^. _userEmail) ] >> return (Just ()))
let let
userSystemFunctions = determineSystemFunctions . Set.fromList $ map CI.mk userSystemFunctions' userSystemFunctions = determineSystemFunctions . Set.fromList $ map CI.mk userSystemFunctions'
@ -253,9 +260,11 @@ decodeUser now UserDefaultConf{..} upsertMode ldapData = do
| otherwise | otherwise
-> throwM CampusUserInvalidIdent -> throwM CampusUserInvalidIdent
userEmail <- if userEmail <- if -- TODO: refactor
| userEmail : _ <- mapMaybe (assertM (elem '@') . either (const Nothing) Just . Text.decodeUtf8') (lookupSome ldapMap $ toList ldapUserEmail) -- | userEmail : _ <- mapMaybe (assertM (elem '@') . either (const Nothing) Just . Text.decodeUtf8') (lookupSome ldapMap $ toList ldapUserEmail)
-> return $ CI.mk userEmail -- -> return $ CI.mk userEmail
| userEmail : _ <- mapMaybe (assertM validEmail . either (const Nothing) Just . Text.decodeUtf8') (lookupSome ldapMap $ toList ldapUserEmail)
-> return $ CI.mk userEmail
| otherwise | otherwise
-> throwM CampusUserInvalidEmail -> throwM CampusUserInvalidEmail
@ -309,7 +318,7 @@ decodeUser now UserDefaultConf{..} upsertMode ldapData = do
, UserCompanyPersonalNumber =. userCompanyPersonalNumber , UserCompanyPersonalNumber =. userCompanyPersonalNumber
, UserCompanyDepartment =. userCompanyDepartment , UserCompanyDepartment =. userCompanyDepartment
] ++ ] ++
[ UserLastAuthentication =. Just now | isLogin ] [ UserLastAuthentication =. Just now | isLogin ]
return (newUser, userUpdate) return (newUser, userUpdate)
where where

View File

@ -2,11 +2,14 @@
-- --
-- SPDX-License-Identifier: AGPL-3.0-or-later -- SPDX-License-Identifier: AGPL-3.0-or-later
-- TODO: why is this Handler.Utils.Profile instead of Utils.Profile?
-- TODO: consider merging with Handler.Utils.Users?
module Handler.Utils.Profile module Handler.Utils.Profile
( checkDisplayName ( checkDisplayName
, validDisplayName , validDisplayName
, fixDisplayName , fixDisplayName
, validPostAddress , validPostAddress
, validEmail, validEmail'
) where ) where
import Import.NoFoundation import Import.NoFoundation
@ -14,10 +17,13 @@ import Import.NoFoundation
import Data.Char import Data.Char
import qualified Data.Text as Text import qualified Data.Text as Text
import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy as LT
import qualified Data.CaseInsensitive as CI
import qualified Data.MultiSet as MultiSet import qualified Data.MultiSet as MultiSet
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Text.Email.Validate as Email
-- | Instead of CI.mk, this still allows use of Text.isInfixOf, etc. -- | Instead of CI.mk, this still allows use of Text.isInfixOf, etc.
stripFold :: Text -> Text stripFold :: Text -> Text
stripFold = Text.toCaseFold . Text.strip stripFold = Text.toCaseFold . Text.strip
@ -72,3 +78,9 @@ validPostAddress (Just StoredMarkup {markupInput = addr})
, 1 < length (LT.lines addr) , 1 < length (LT.lines addr)
= True = True
validPostAddress _ = False validPostAddress _ = False
validEmail :: Email -> Bool -- Email = Text
validEmail = Email.isValid . encodeUtf8
validEmail' :: UserEmail -> Bool -- UserEmail = CI Text
validEmail' = Email.isValid . encodeUtf8 . CI.original

View File

@ -2,6 +2,7 @@
-- --
-- SPDX-License-Identifier: AGPL-3.0-or-later -- SPDX-License-Identifier: AGPL-3.0-or-later
-- NOTE: Also see Handler.Utils.Profile for similar utilities
module Handler.Utils.Users module Handler.Utils.Users
( computeUserAuthenticationDigest ( computeUserAuthenticationDigest
, Digest, SHA3_256 , Digest, SHA3_256
@ -44,6 +45,7 @@ import qualified Data.Conduit.Combinators as C
import qualified Data.MultiSet as MultiSet import qualified Data.MultiSet as MultiSet
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Text as Text import qualified Data.Text as Text
import Handler.Utils.Profile
import Jobs.Types(Job, JobChildren) import Jobs.Types(Job, JobChildren)
@ -73,7 +75,7 @@ getPostalPreferenceAndAddress usr@User{..} =
(((userPrefersPostal || isNothing userPinPassword) && postPossible) || emailImpossible, pa) (((userPrefersPostal || isNothing userPinPassword) && postPossible) || emailImpossible, pa)
where where
orgEmail = CI.original userEmail orgEmail = CI.original userEmail
emailImpossible = not ('@' `textElem` orgEmail && '.' `textElem` orgEmail) emailImpossible = validEmail orgEmail
postPossible = isJust pa postPossible = isJust pa
pa = getPostalAddress usr pa = getPostalAddress usr

View File

@ -9,6 +9,7 @@ module Jobs.Handler.SynchroniseLdap
import Import import Import
import qualified Data.CaseInsensitive as CI
import qualified Data.Conduit.List as C import qualified Data.Conduit.List as C
import Auth.LDAP import Auth.LDAP
@ -47,13 +48,13 @@ dispatchJobSynchroniseLdapUser jUser = JobHandlerException $ do
case appLdapPool of case appLdapPool of
Just ldapPool -> Just ldapPool ->
runDB . void . runMaybeT . handleExc $ do runDB . void . runMaybeT . handleExc $ do
user@User{userIdent} <- MaybeT $ get jUser user@User{userIdent,userLdapPrimaryKey} <- MaybeT $ get jUser
let upsertIdent = maybe userIdent CI.mk userLdapPrimaryKey
$logInfoS "SynchroniseLdap" [st|Synchronising #{userIdent}|] $logInfoS "SynchroniseLdap" [st|Synchronising #{userIdent}|]
reTestAfter <- getsYesod $ view _appLdapReTestFailover reTestAfter <- getsYesod $ view _appLdapReTestFailover
ldapAttrs <- MaybeT $ campusUserReTest' ldapPool ((>= reTestAfter) . realToFrac) FailoverUnlimited user ldapAttrs <- MaybeT $ campusUserReTest' ldapPool ((>= reTestAfter) . realToFrac) FailoverUnlimited user
void . lift $ upsertCampusUser (UpsertCampusUserLdapSync userIdent) ldapAttrs void . lift $ upsertCampusUser (UpsertCampusUserLdapSync upsertIdent) ldapAttrs
Nothing -> Nothing ->
throwM SynchroniseLdapNoLdap throwM SynchroniseLdapNoLdap
where where