Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
fdf4c61
Make sure to actually wrap the action in 'wrapMonadClientSem'
isovector Sep 17, 2021
b239949
Implement wrapMonadClient in terms of wrapMonadClientSem
isovector Sep 17, 2021
c66961d
Pull out IdP effect
isovector Sep 17, 2021
2943335
Push Member IdP constraints throughout
isovector Sep 17, 2021
18bebc6
Pull application logic out of Data and into App
isovector Sep 17, 2021
d58dc66
Use application-level functions instead
isovector Sep 17, 2021
92401dd
Remove deleteTeam from Data too
isovector Sep 17, 2021
6564df4
Get rid of wrapMonadClientWithEnvSem
isovector Sep 17, 2021
ed760c3
Implement wrapSpar
isovector Sep 17, 2021
016d39c
Undo accidental formatting
isovector Sep 17, 2021
c93a8c5
Update cabal
isovector Sep 17, 2021
3c5fb71
make format
isovector Sep 17, 2021
4173291
Update changelog
isovector Sep 17, 2021
dc159fa
Merge branch 'wrap-monad-client-sem' into idp-effect
isovector Sep 17, 2021
55f9ba8
Get rid of the untouchable variable in liftSem
isovector Sep 17, 2021
4e9ebc5
Be very careful about wrapping in the same places
isovector Sep 17, 2021
c585b91
Resort exports
isovector Sep 17, 2021
c79130d
Changelog
isovector Sep 17, 2021
e4a761c
Merge branch 'develop' into idp-effect
isovector Sep 17, 2021
6c7ff76
DefaultSsoCode effect
isovector Sep 18, 2021
2e0319c
ScimTokenStore effect
isovector Sep 18, 2021
d1f9158
wip BindCookie effect
isovector Sep 18, 2021
a62a7eb
Forgot some callsites
isovector Sep 18, 2021
c4d33b7
Merge branch 'idp-effect' of github.com:wireapp/wire-server into idp-…
isovector Sep 18, 2021
29befdb
Get tests compiling again
isovector Sep 18, 2021
dc14528
Get everything compiling
isovector Sep 18, 2021
2de4c63
remove runSparCassSem
isovector Sep 18, 2021
1d800f5
Merge branch 'idp-effect' into misc-effects
isovector Sep 18, 2021
1a708f4
Change the tests to use IdP
isovector Sep 19, 2021
971a581
Finish all SAMLUser and IdP effects refs in tests
isovector Sep 19, 2021
0b47ac2
Excise all references to IdP and SAMLUser effects
isovector Sep 19, 2021
5292607
Merge branch 'idp-effect' into misc-effects
isovector Sep 19, 2021
d76dbf7
make format
isovector Sep 19, 2021
4494e1d
Merge branch 'idp-effect' into misc-effects
isovector Sep 19, 2021
4abee7b
make format
isovector Sep 19, 2021
4c61c14
Remove all references to new effects
isovector Sep 19, 2021
246bb83
make format
isovector Sep 19, 2021
f5bf9af
Add ScimUserTimesStore effect
isovector Sep 20, 2021
c459aa9
ScimExternalIdStore effect
isovector Sep 20, 2021
ae815cb
make format
isovector Sep 20, 2021
15a70a7
Implement scimExternalIdStoreToCassandra
isovector Sep 20, 2021
92ea468
Merge branch 'develop' into misc-effects
isovector Sep 20, 2021
26824fc
Use Members when appropriate
isovector Sep 20, 2021
6eb9f0b
make format
isovector Sep 20, 2021
6e45f86
Fixes.
fisx Sep 21, 2021
88ab682
Merge branch 'develop' into misc-effects
isovector Sep 21, 2021
18ca728
Remove unwritten BindCookie effect modules
isovector Sep 22, 2021
7b751d7
SAMLUser -> SAMLUserStore
isovector Sep 22, 2021
08c6b16
Don't do extraneous lifting
isovector Sep 22, 2021
ddb96be
Changelog.d
isovector Sep 22, 2021
05cd55d
AReqIDStore effect
isovector Sep 22, 2021
8bb391c
make format
isovector Sep 22, 2021
60d55f0
AssIDStore effect
isovector Sep 22, 2021
8cc1035
Update Spar/API
isovector Sep 22, 2021
ccba153
Fix tests
isovector Sep 22, 2021
70d56a5
make format
isovector Sep 22, 2021
6cb4245
Add store/getVerdictFormat to AReqIDStore
isovector Sep 23, 2021
383546d
BindCookieStore effect
isovector Sep 23, 2021
34ef4a2
Remove runSparCass*
isovector Sep 23, 2021
d424429
Remove cassandra-specific utils
isovector Sep 23, 2021
0a8714b
make format
isovector Sep 23, 2021
210afc4
Merge branch 'develop' into last-spar-effects
isovector Sep 23, 2021
c6888dc
changelog.d
isovector Sep 23, 2021
151b86b
Fake commit to rerun CI
isovector Sep 24, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/5-internal/last-spar-effects
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Polysemize the remainder of Spar's Cassandra effects
8 changes: 7 additions & 1 deletion services/spar/spar.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cabal-version: 1.12
--
-- see: https://github.com/sol/hpack
--
-- hash: f135fc7f6d1e85694286faaeb615c1808dedee43fd207e59f50864481c2a9cca
-- hash: d04f829f6801dc459cf2f535b387c77caf06d3d99c2d95c9b46c469c1ec8b890

name: spar
version: 0.1
Expand Down Expand Up @@ -34,6 +34,12 @@ library
Spar.Scim.Auth
Spar.Scim.Types
Spar.Scim.User
Spar.Sem.AReqIDStore
Spar.Sem.AReqIDStore.Cassandra
Spar.Sem.AssIDStore
Spar.Sem.AssIDStore.Cassandra
Spar.Sem.BindCookieStore
Spar.Sem.BindCookieStore.Cassandra
Spar.Sem.DefaultSsoCode
Spar.Sem.DefaultSsoCode.Cassandra
Spar.Sem.IdP
Expand Down
53 changes: 45 additions & 8 deletions services/spar/src/Spar/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,17 @@ import qualified SAML2.WebSSO as SAML
import Servant
import qualified Servant.Multipart as Multipart
import Spar.App
import qualified Spar.Data as Data hiding (clearReplacedBy, deleteIdPRawMetadata, getIdPConfig, getIdPConfigsByTeam, getIdPIdByIssuerWithTeam, getIdPIdByIssuerWithoutTeam, getIdPRawMetadata, setReplacedBy, storeIdPConfig, storeIdPRawMetadata)
import qualified Spar.Data as Data (GetIdPResult (..), Replaced (..), Replacing (..))
import Spar.Error
import qualified Spar.Intra.Brig as Brig
import qualified Spar.Intra.Galley as Galley
import Spar.Orphans ()
import Spar.Scim
import Spar.Sem.AReqIDStore (AReqIDStore)
import qualified Spar.Sem.AReqIDStore as AReqIDStore
import Spar.Sem.AssIDStore (AssIDStore)
import Spar.Sem.BindCookieStore (BindCookieStore)
import qualified Spar.Sem.BindCookieStore as BindCookieStore
import Spar.Sem.DefaultSsoCode (DefaultSsoCode)
import qualified Spar.Sem.DefaultSsoCode as DefaultSsoCode
import qualified Spar.Sem.IdP as IdPEffect
Expand All @@ -84,7 +89,21 @@ app ctx =
SAML.setHttpCachePolicy $
serve (Proxy @API) (hoistServer (Proxy @API) (SAML.nt @SparError @(Spar _) ctx) (api $ sparCtxOpts ctx) :: Server API)

api :: Members '[ScimExternalIdStore, ScimUserTimesStore, ScimTokenStore, DefaultSsoCode, IdPEffect.IdP, SAMLUserStore] r => Opts -> ServerT API (Spar r)
api ::
Members
'[ BindCookieStore,
AssIDStore,
AReqIDStore,
ScimExternalIdStore,
ScimUserTimesStore,
ScimTokenStore,
DefaultSsoCode,
IdPEffect.IdP,
SAMLUserStore
]
r =>
Opts ->
ServerT API (Spar r)
api opts =
apiSSO opts
:<|> authreqPrecheck
Expand All @@ -93,7 +112,19 @@ api opts =
:<|> apiScim
:<|> apiINTERNAL

apiSSO :: Members '[ScimTokenStore, DefaultSsoCode, IdPEffect.IdP, SAMLUserStore] r => Opts -> ServerT APISSO (Spar r)
apiSSO ::
Members
'[ BindCookieStore,
AssIDStore,
AReqIDStore,
ScimTokenStore,
DefaultSsoCode,
IdPEffect.IdP,
SAMLUserStore
]
r =>
Opts ->
ServerT APISSO (Spar r)
apiSSO opts =
SAML.meta appName (sparSPIssuer Nothing) (sparResponseURI Nothing)
:<|> (\tid -> SAML.meta appName (sparSPIssuer (Just tid)) (sparResponseURI (Just tid)))
Expand Down Expand Up @@ -131,7 +162,7 @@ authreqPrecheck msucc merr idpid =
*> return NoContent

authreq ::
Member IdPEffect.IdP r =>
Members '[BindCookieStore, AssIDStore, AReqIDStore, IdPEffect.IdP] r =>
NominalDiffTime ->
DoInitiate ->
Maybe UserId ->
Expand All @@ -150,23 +181,23 @@ authreq authreqttl _ zusr msucc merr idpid = do
WireIdPAPIV1 -> Nothing
WireIdPAPIV2 -> Just $ idp ^. SAML.idpExtraInfo . wiTeam
SAML.authreq authreqttl (sparSPIssuer mbtid) idpid
wrapMonadClient $ Data.storeVerdictFormat authreqttl reqid vformat
wrapMonadClientSem $ AReqIDStore.storeVerdictFormat authreqttl reqid vformat
cky <- initializeBindCookie zusr authreqttl
SAML.logger SAML.Debug $ "setting bind cookie: " <> show cky
pure $ addHeader cky form

-- | If the user is already authenticated, create bind cookie with a given life expectancy and our
-- domain, and store it in C*. If the user is not authenticated, return a deletion 'SetCookie'
-- value that deletes any bind cookies on the client.
initializeBindCookie :: Maybe UserId -> NominalDiffTime -> Spar r SetBindCookie
initializeBindCookie :: Member BindCookieStore r => Maybe UserId -> NominalDiffTime -> Spar r SetBindCookie
initializeBindCookie zusr authreqttl = do
DerivedOpts {derivedOptsBindCookiePath} <- asks (derivedOpts . sparCtxOpts)
msecret <-
if isJust zusr
then liftIO $ Just . cs . ES.encode <$> randBytes 32
else pure Nothing
cky <- fmap SetBindCookie . SAML.toggleCookie derivedOptsBindCookiePath $ (,authreqttl) <$> msecret
forM_ zusr $ \userid -> wrapMonadClientWithEnv $ Data.insertBindCookie cky userid authreqttl
forM_ zusr $ \userid -> wrapMonadClientSem $ BindCookieStore.insert cky userid authreqttl
pure cky

redirectURLMaxLength :: Int
Expand All @@ -187,7 +218,13 @@ validateRedirectURL uri = do
unless ((SBS.length $ URI.serializeURIRef' uri) <= redirectURLMaxLength) $ do
throwSpar $ SparBadInitiateLoginQueryParams "url-too-long"

authresp :: forall r. Members '[ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r => Maybe TeamId -> Maybe ST -> SAML.AuthnResponseBody -> Spar r Void
authresp ::
forall r.
Members '[BindCookieStore, AssIDStore, AReqIDStore, ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r =>
Maybe TeamId ->
Maybe ST ->
SAML.AuthnResponseBody ->
Spar r Void
authresp mbtid ckyraw arbody = logErrors $ SAML.authresp mbtid (sparSPIssuer mbtid) (sparResponseURI mbtid) go arbody
where
cky :: Maybe BindCookie
Expand Down
139 changes: 84 additions & 55 deletions services/spar/src/Spar/App.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ module Spar.App
( Spar (..),
Env (..),
toLevel,
wrapMonadClientWithEnv,
wrapMonadClient,
wrapMonadClientSem,
verdictHandler,
GetUserResult (..),
Expand All @@ -41,14 +39,12 @@ module Spar.App
deleteTeam,
wrapSpar,
liftSem,
liftMonadClient,
)
where

import Bilge
import Brig.Types (ManagedBy (..), User, userId, userTeam)
import Brig.Types.Intra (AccountStatus (..), accountStatus, accountUser)
import Cassandra
import qualified Cassandra as Cas
import Control.Exception (assert)
import Control.Lens hiding ((.=))
Expand All @@ -68,7 +64,9 @@ import Imports hiding (log)
import qualified Network.HTTP.Types.Status as Http
import qualified Network.Wai.Utilities.Error as Wai
import Polysemy
import Polysemy.Error
import Polysemy.Final
import qualified Polysemy.Reader as ReaderEff
import SAML2.Util (renderURI)
import SAML2.WebSSO
( Assertion (..),
Expand All @@ -84,7 +82,6 @@ import SAML2.WebSSO
SPStoreIdP (getIdPConfigByIssuerOptionalSPId),
UnqualifiedNameID (..),
explainDeniedReason,
fromTime,
idpExtraInfo,
idpId,
uidTenant,
Expand All @@ -93,11 +90,20 @@ import qualified SAML2.WebSSO as SAML
import qualified SAML2.WebSSO.Types.Email as SAMLEmail
import Servant
import qualified Servant.Multipart as Multipart
import qualified Spar.Data as Data hiding (deleteSAMLUser, deleteSAMLUsersByIssuer, getIdPConfig, getSAMLAnyUserByIssuer, getSAMLSomeUsersByIssuer, getSAMLUser, insertSAMLUser, storeIdPConfig)
import qualified Spar.Data as Data (GetIdPResult (..))
import Spar.Error
import qualified Spar.Intra.Brig as Intra
import qualified Spar.Intra.Galley as Intra
import Spar.Orphans ()
import Spar.Sem.AReqIDStore (AReqIDStore)
import qualified Spar.Sem.AReqIDStore as AReqIDStore
import Spar.Sem.AReqIDStore.Cassandra (aReqIDStoreToCassandra, ttlErrorToSparError)
import Spar.Sem.AssIDStore (AssIDStore)
import qualified Spar.Sem.AssIDStore as AssIDStore
import Spar.Sem.AssIDStore.Cassandra (assIDStoreToCassandra)
import Spar.Sem.BindCookieStore (BindCookieStore)
import qualified Spar.Sem.BindCookieStore as BindCookieStore
import Spar.Sem.BindCookieStore.Cassandra (bindCookieStoreToCassandra)
import Spar.Sem.DefaultSsoCode (DefaultSsoCode)
import Spar.Sem.DefaultSsoCode.Cassandra (defaultSsoCodeToCassandra)
import Spar.Sem.IdP (GetIdPResult (..))
Expand Down Expand Up @@ -186,15 +192,15 @@ toLevel = \case
SAML.Debug -> Log.Debug
SAML.Trace -> Log.Trace

instance SPStoreID AuthnRequest (Spar r) where
storeID i r = wrapMonadClientWithEnv $ Data.storeAReqID i r
unStoreID r = wrapMonadClient $ Data.unStoreAReqID r
isAliveID r = wrapMonadClient $ Data.isAliveAReqID r
instance Member AReqIDStore r => SPStoreID AuthnRequest (Spar r) where
storeID i r = wrapMonadClientSem $ AReqIDStore.store i r
unStoreID r = wrapMonadClientSem $ AReqIDStore.unStore r
isAliveID r = wrapMonadClientSem $ AReqIDStore.isAlive r

instance SPStoreID Assertion (Spar r) where
storeID i r = wrapMonadClientWithEnv $ Data.storeAssID i r
unStoreID r = wrapMonadClient $ Data.unStoreAssID r
isAliveID r = wrapMonadClient $ Data.isAliveAssID r
instance Member AssIDStore r => SPStoreID Assertion (Spar r) where
storeID i r = wrapMonadClientSem $ AssIDStore.store i r
unStoreID r = wrapMonadClientSem $ AssIDStore.unStore r
isAliveID r = wrapMonadClientSem $ AssIDStore.isAlive r

instance Member IdPEffect.IdP r => SPStoreIdP SparError (Spar r) where
type IdPConfigExtra (Spar r) = WireIdP
Expand All @@ -215,13 +221,6 @@ instance Member IdPEffect.IdP r => SPStoreIdP SparError (Spar r) where
res@(Data.GetIdPNonUnique _) -> throwSpar $ SparIdPNotFound (cs $ show res)
res@(Data.GetIdPWrongTeam _) -> throwSpar $ SparIdPNotFound (cs $ show res)

-- | 'wrapMonadClient' with an 'Env' in a 'ReaderT', and exceptions. If you
-- don't need either of those, 'wrapMonadClient' will suffice.
wrapMonadClientWithEnv :: forall r a. ReaderT Data.Env (ExceptT TTLError Cas.Client) a -> Spar r a
wrapMonadClientWithEnv action = do
denv <- Data.mkEnv <$> (sparCtxOpts <$> ask) <*> (fromTime <$> getNow)
either (throwSpar . SparCassandraTTLError) pure =<< wrapMonadClient (runExceptT $ action `runReaderT` denv)

instance Member (Final IO) r => Catch.MonadThrow (Sem r) where
throwM = embedFinal . Catch.throwM @IO

Expand All @@ -232,22 +231,6 @@ instance Member (Final IO) r => Catch.MonadCatch (Sem r) where
handler' <- bindS handler
pure $ m' `Catch.catch` \e -> handler' $ e <$ st

-- | Call a cassandra command in the 'Spar' monad. Catch all exceptions and re-throw them as 500 in
-- Handler.
wrapMonadClient :: Cas.Client a -> Spar r a
wrapMonadClient action =
Spar $ do
ctx <- asks sparCtxCas
fromSpar $ wrapMonadClientSem $ embedFinal @IO $ runClient ctx action

-- | Lift a cassandra command into the 'Spar' monad. Like 'wrapMonadClient',
-- but doesn't catch any exceptions.
liftMonadClient :: Cas.Client a -> Spar r a
liftMonadClient action =
Spar $ do
ctx <- asks sparCtxCas
lift $ lift $ embedFinal @IO $ runClient ctx action

-- | Call a 'Sem' command in the 'Spar' monad. Catch all (IO) exceptions and
-- re-throw them as 500 in Handler.
wrapMonadClientSem :: Sem r a -> Spar r a
Expand Down Expand Up @@ -425,7 +408,27 @@ bindUser buid userref = do
Ephemeral -> err oldStatus
PendingInvitation -> Intra.setStatus buid Active

instance (r ~ '[ScimExternalIdStore, ScimUserTimesStore, ScimTokenStore, DefaultSsoCode, IdPEffect.IdP, SAMLUserStore, Embed (Cas.Client), Embed IO, Final IO]) => SPHandler SparError (Spar r) where
instance
( r
~ '[ BindCookieStore,
AssIDStore,
AReqIDStore,
ScimExternalIdStore,
ScimUserTimesStore,
ScimTokenStore,
DefaultSsoCode,
IdPEffect.IdP,
SAMLUserStore,
Embed (Cas.Client),
ReaderEff.Reader Opts,
Error TTLError,
Error SparError,
Embed IO,
Final IO
]
) =>
SPHandler SparError (Spar r)
where
type NTCTX (Spar r) = Env
nt :: forall a. Env -> Spar r a -> Handler a
nt ctx (Spar action) = do
Expand All @@ -434,18 +437,25 @@ instance (r ~ '[ScimExternalIdStore, ScimUserTimesStore, ScimTokenStore, Default
where
actionHandler :: Handler (Either SparError a)
actionHandler =
liftIO $
runFinal $
embedToFinal @IO $
interpretClientToIO (sparCtxCas ctx) $
samlUserStoreToCassandra @Cas.Client $
idPToCassandra @Cas.Client $
defaultSsoCodeToCassandra $
scimTokenStoreToCassandra $
scimUserTimesStoreToCassandra $
scimExternalIdStoreToCassandra $
runExceptT $
runReaderT action ctx
fmap join $
liftIO $
runFinal $
embedToFinal @IO $
runError @SparError $
ttlErrorToSparError $
ReaderEff.runReader (sparCtxOpts ctx) $
interpretClientToIO (sparCtxCas ctx) $
samlUserStoreToCassandra @Cas.Client $
idPToCassandra @Cas.Client $
defaultSsoCodeToCassandra $
scimTokenStoreToCassandra $
scimUserTimesStoreToCassandra $
scimExternalIdStoreToCassandra $
aReqIDStoreToCassandra $
assIDStoreToCassandra $
bindCookieStoreToCassandra $
runExceptT $
runReaderT action ctx
throwErrorAsHandlerException :: Either SparError a -> Handler a
throwErrorAsHandlerException (Left err) =
sparToServerErrorWithLogging (sparCtxLogger ctx) err >>= throwError
Expand Down Expand Up @@ -475,14 +485,21 @@ instance Intra.MonadSparToGalley (Spar r) where
-- signed in-response-to info in the assertions matches the unsigned in-response-to field in the
-- 'SAML.Response', and fills in the response id in the header if missing, we can just go for the
-- latter.
verdictHandler :: HasCallStack => Members '[ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r => Maybe BindCookie -> Maybe TeamId -> SAML.AuthnResponse -> SAML.AccessVerdict -> Spar r SAML.ResponseVerdict
verdictHandler ::
HasCallStack =>
Members '[BindCookieStore, AReqIDStore, ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r =>
Maybe BindCookie ->
Maybe TeamId ->
SAML.AuthnResponse ->
SAML.AccessVerdict ->
Spar r SAML.ResponseVerdict
verdictHandler cky mbteam aresp verdict = do
-- [3/4.1.4.2]
-- <SubjectConfirmation> [...] If the containing message is in response to an <AuthnRequest>, then
-- the InResponseTo attribute MUST match the request's ID.
SAML.logger SAML.Debug $ "entering verdictHandler: " <> show (fromBindCookie <$> cky, aresp, verdict)
reqid <- either (throwSpar . SparNoRequestRefInResponse . cs) pure $ SAML.rspInResponseTo aresp
format :: Maybe VerdictFormat <- wrapMonadClient $ Data.getVerdictFormat reqid
format :: Maybe VerdictFormat <- wrapMonadClientSem $ AReqIDStore.getVerdictFormat reqid
resp <- case format of
Just (VerdictFormatWeb) ->
verdictHandlerResult cky mbteam verdict >>= verdictHandlerWeb
Expand All @@ -500,7 +517,13 @@ data VerdictHandlerResult
| VerifyHandlerError {_vhrLabel :: ST, _vhrMessage :: ST}
deriving (Eq, Show)

verdictHandlerResult :: HasCallStack => Members '[ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r => Maybe BindCookie -> Maybe TeamId -> SAML.AccessVerdict -> Spar r VerdictHandlerResult
verdictHandlerResult ::
HasCallStack =>
Members '[BindCookieStore, ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r =>
Maybe BindCookie ->
Maybe TeamId ->
SAML.AccessVerdict ->
Spar r VerdictHandlerResult
verdictHandlerResult bindCky mbteam verdict = do
SAML.logger SAML.Debug $ "entering verdictHandlerResult: " <> show (fromBindCookie <$> bindCky)
result <- catchVerdictErrors $ verdictHandlerResultCore bindCky mbteam verdict
Expand Down Expand Up @@ -539,13 +562,19 @@ moveUserToNewIssuer oldUserRef newUserRef uid = do
Intra.setBrigUserVeid uid (UrefOnly newUserRef)
wrapMonadClientSem $ SAMLUserStore.delete uid oldUserRef

verdictHandlerResultCore :: HasCallStack => Members '[ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r => Maybe BindCookie -> Maybe TeamId -> SAML.AccessVerdict -> Spar r VerdictHandlerResult
verdictHandlerResultCore ::
HasCallStack =>
Members '[BindCookieStore, ScimTokenStore, IdPEffect.IdP, SAMLUserStore] r =>
Maybe BindCookie ->
Maybe TeamId ->
SAML.AccessVerdict ->
Spar r VerdictHandlerResult
verdictHandlerResultCore bindCky mbteam = \case
SAML.AccessDenied reasons -> do
pure $ VerifyHandlerDenied reasons
SAML.AccessGranted userref -> do
uid :: UserId <- do
viaBindCookie <- maybe (pure Nothing) (wrapMonadClient . Data.lookupBindCookie) bindCky
viaBindCookie <- maybe (pure Nothing) (wrapMonadClientSem . BindCookieStore.lookup) bindCky
viaSparCassandra <- getUserIdByUref mbteam userref
-- race conditions: if the user has been created on spar, but not on brig, 'getUser'
-- returns 'Nothing'. this is ok assuming 'createUser', 'bindUser' (called below) are
Expand Down
Loading