Skip to content

Commit fe32ce3

Browse files
authored
Spar Polysemy: Split IdPRawMetadataStore from IdP (#1924)
* Separate IdPRawMetadataStore * make format * Changelog * Fix bad merge * Split out IdPSpec also * make format * hpack
1 parent 187d52c commit fe32ce3

File tree

12 files changed

+221
-137
lines changed

12 files changed

+221
-137
lines changed

changelog.d/5-internal/split-eff1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Separate IdPRawMetadataStore effect from IdP effect

services/spar/spar.cabal

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cabal-version: 1.12
44
--
55
-- see: https://github.com/sol/hpack
66
--
7-
-- hash: a0e25b55baaade0d8e5c5317b255ef5191d861abfde4369ef34ffb6d77bc8e0d
7+
-- hash: 6007f4f8ec59cf0a438cd7831dc87bda6d60acd7865f6c251bd6f2da5617b381
88

99
name: spar
1010
version: 0.1
@@ -51,6 +51,9 @@ library
5151
Spar.Sem.IdP
5252
Spar.Sem.IdP.Cassandra
5353
Spar.Sem.IdP.Mem
54+
Spar.Sem.IdPRawMetadataStore
55+
Spar.Sem.IdPRawMetadataStore.Cassandra
56+
Spar.Sem.IdPRawMetadataStore.Mem
5457
Spar.Sem.Logger
5558
Spar.Sem.Logger.TinyLog
5659
Spar.Sem.Now
@@ -499,6 +502,7 @@ test-suite spec
499502
Test.Spar.Intra.BrigSpec
500503
Test.Spar.Roundtrip.ByteString
501504
Test.Spar.ScimSpec
505+
Test.Spar.Sem.IdPRawMetadataStoreSpec
502506
Test.Spar.Sem.IdPSpec
503507
Test.Spar.TypesSpec
504508
Paths_spar

services/spar/src/Spar/API.hs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ import qualified Spar.Sem.DefaultSsoCode as DefaultSsoCode
7878
import Spar.Sem.GalleyAccess (GalleyAccess)
7979
import qualified Spar.Sem.GalleyAccess as GalleyAccess
8080
import qualified Spar.Sem.IdP as IdPEffect
81+
import Spar.Sem.IdPRawMetadataStore (IdPRawMetadataStore)
82+
import qualified Spar.Sem.IdPRawMetadataStore as IdPRawMetadataStore
8183
import Spar.Sem.Logger (Logger)
8284
import qualified Spar.Sem.Logger as Logger
8385
import Spar.Sem.Now (Now)
@@ -119,6 +121,7 @@ api ::
119121
ScimTokenStore,
120122
DefaultSsoCode,
121123
IdPEffect.IdP,
124+
IdPRawMetadataStore,
122125
SAMLUserStore,
123126
Random,
124127
Error SparError,
@@ -181,6 +184,7 @@ apiIDP ::
181184
BrigAccess,
182185
ScimTokenStore,
183186
IdPEffect.IdP,
187+
IdPRawMetadataStore,
184188
SAMLUserStore,
185189
Error SparError
186190
]
@@ -380,14 +384,21 @@ idpGet zusr idpid = withDebugLog "idpGet" (Just . show . (^. SAML.idpId)) $ do
380384
pure idp
381385

382386
idpGetRaw ::
383-
Members '[GalleyAccess, BrigAccess, IdPEffect.IdP, Error SparError] r =>
387+
Members
388+
'[ GalleyAccess,
389+
BrigAccess,
390+
IdPEffect.IdP,
391+
IdPRawMetadataStore,
392+
Error SparError
393+
]
394+
r =>
384395
Maybe UserId ->
385396
SAML.IdPId ->
386397
Sem r RawIdPMetadata
387398
idpGetRaw zusr idpid = do
388399
idp <- getIdPConfig idpid
389400
_ <- authorizeIdP zusr idp
390-
IdPEffect.getRawMetadata idpid >>= \case
401+
IdPRawMetadataStore.get idpid >>= \case
391402
Just txt -> pure $ RawIdPMetadata txt
392403
Nothing -> throwSparSem $ SparIdPNotFound (cs $ show idpid)
393404

@@ -426,6 +437,7 @@ idpDelete ::
426437
ScimTokenStore,
427438
SAMLUserStore,
428439
IdPEffect.IdP,
440+
IdPRawMetadataStore,
429441
Error SparError
430442
]
431443
r =>
@@ -462,7 +474,7 @@ idpDelete zusr idpid (fromMaybe False -> purge) = withDebugLog "idpDelete" (cons
462474
-- Delete IdP config
463475
do
464476
IdPEffect.deleteConfig idp
465-
IdPEffect.deleteRawMetadata idpid
477+
IdPRawMetadataStore.delete idpid
466478
return NoContent
467479
where
468480
updateOldIssuers :: IdP -> Sem r ()
@@ -492,6 +504,7 @@ idpCreate ::
492504
GalleyAccess,
493505
BrigAccess,
494506
ScimTokenStore,
507+
IdPRawMetadataStore,
495508
IdPEffect.IdP,
496509
Error SparError
497510
]
@@ -512,6 +525,7 @@ idpCreateXML ::
512525
BrigAccess,
513526
ScimTokenStore,
514527
IdPEffect.IdP,
528+
IdPRawMetadataStore,
515529
Error SparError
516530
]
517531
r =>
@@ -526,7 +540,7 @@ idpCreateXML zusr raw idpmeta mReplaces (fromMaybe defWireIdPAPIVersion -> apive
526540
GalleyAccess.assertSSOEnabled teamid
527541
assertNoScimOrNoIdP teamid
528542
idp <- validateNewIdP apiversion idpmeta teamid mReplaces
529-
IdPEffect.storeRawMetadata (idp ^. SAML.idpId) raw
543+
IdPRawMetadataStore.store (idp ^. SAML.idpId) raw
530544
storeIdPConfig idp
531545
forM_ mReplaces $ \replaces -> do
532546
IdPEffect.setReplacedBy (Data.Replaced replaces) (Data.Replacing (idp ^. SAML.idpId))
@@ -635,6 +649,7 @@ idpUpdate ::
635649
GalleyAccess,
636650
BrigAccess,
637651
IdPEffect.IdP,
652+
IdPRawMetadataStore,
638653
Error SparError
639654
]
640655
r =>
@@ -651,6 +666,7 @@ idpUpdateXML ::
651666
GalleyAccess,
652667
BrigAccess,
653668
IdPEffect.IdP,
669+
IdPRawMetadataStore,
654670
Error SparError
655671
]
656672
r =>
@@ -662,7 +678,7 @@ idpUpdateXML ::
662678
idpUpdateXML zusr raw idpmeta idpid = withDebugLog "idpUpdate" (Just . show . (^. SAML.idpId)) $ do
663679
(teamid, idp) <- validateIdPUpdate zusr idpmeta idpid
664680
GalleyAccess.assertSSOEnabled teamid
665-
IdPEffect.storeRawMetadata (idp ^. SAML.idpId) raw
681+
IdPRawMetadataStore.store (idp ^. SAML.idpId) raw
666682
-- (if raw metadata is stored and then spar goes out, raw metadata won't match the
667683
-- structured idp config. since this will lead to a 5xx response, the client is epected to
668684
-- try again, which would clean up cassandra state.)

services/spar/src/Spar/CanonicalInterpreter.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import Spar.Sem.GalleyAccess (GalleyAccess)
2626
import Spar.Sem.GalleyAccess.Http (galleyAccessToHttp)
2727
import qualified Spar.Sem.IdP as IdPEffect
2828
import Spar.Sem.IdP.Cassandra (idPToCassandra)
29+
import Spar.Sem.IdPRawMetadataStore (IdPRawMetadataStore)
30+
import Spar.Sem.IdPRawMetadataStore.Cassandra (idpRawMetadataStoreToCassandra)
2931
import Spar.Sem.Logger (Logger)
3032
import Spar.Sem.Logger.TinyLog (loggerToTinyLog, stringLoggerToTinyLog)
3133
import Spar.Sem.Now (Now)
@@ -60,6 +62,7 @@ type CanonicalEffs =
6062
ScimTokenStore,
6163
DefaultSsoCode,
6264
IdPEffect.IdP,
65+
IdPRawMetadataStore,
6366
SAMLUserStore,
6467
Embed (Cas.Client),
6568
BrigAccess,
@@ -95,6 +98,7 @@ runSparToIO ctx action =
9598
. brigAccessToHttp (sparCtxHttpManager ctx) (sparCtxHttpBrig ctx)
9699
. interpretClientToIO (sparCtxCas ctx)
97100
. samlUserStoreToCassandra
101+
. idpRawMetadataStoreToCassandra
98102
. idPToCassandra
99103
. defaultSsoCodeToCassandra
100104
. scimTokenStoreToCassandra

services/spar/src/Spar/Sem/IdP.hs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ data IdP m a where
3636
-- affects _wiReplacedBy in GetConfig
3737
SetReplacedBy :: Replaced -> Replacing -> IdP m ()
3838
ClearReplacedBy :: Replaced -> IdP m ()
39-
-- TODO(sandy): maybe this wants to be a separate effect
40-
-- data Metadata m a where
41-
StoreRawMetadata :: SAML.IdPId -> Text -> IdP m ()
42-
GetRawMetadata :: SAML.IdPId -> IdP m (Maybe Text)
43-
DeleteRawMetadata :: SAML.IdPId -> IdP m ()
4439

4540
deriving stock instance Show (IdP m a)
4641

services/spar/src/Spar/Sem/IdP/Cassandra.hs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,3 @@ idPToCassandra =
2929
in Data.deleteIdPConfig idpid issuer team
3030
SetReplacedBy r r11 -> Data.setReplacedBy r r11
3131
ClearReplacedBy r -> Data.clearReplacedBy r
32-
StoreRawMetadata i t -> Data.storeIdPRawMetadata i t
33-
GetRawMetadata i -> Data.getIdPRawMetadata i
34-
DeleteRawMetadata i -> Data.deleteIdPRawMetadata i

services/spar/src/Spar/Sem/IdP/Mem.hs

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-}
22

3-
module Spar.Sem.IdP.Mem (idPToMem, IS) where
3+
module Spar.Sem.IdP.Mem (idPToMem, TypedState) where
44

5-
import Control.Lens ((%~), (.~), (^.), _1, _2)
5+
import Control.Lens ((.~), (^.))
66
import Data.Id (TeamId)
77
import qualified Data.Map as M
88
import Imports
@@ -12,45 +12,35 @@ import qualified SAML2.WebSSO.Types as SAML
1212
import qualified Spar.Sem.IdP as Eff
1313
import qualified Wire.API.User.IdentityProvider as IP
1414

15-
type IS = (TypedState, RawState)
16-
1715
type TypedState = Map SAML.IdPId IP.IdP
1816

19-
type RawState = Map SAML.IdPId Text
20-
2117
idPToMem ::
2218
forall r a.
2319
Sem (Eff.IdP ': r) a ->
24-
Sem r (IS, a)
20+
Sem r (TypedState, a)
2521
idPToMem = evState . evEff
2622
where
27-
evState :: Sem (State IS : r) a -> Sem r (IS, a)
23+
evState :: Sem (State TypedState : r) a -> Sem r (TypedState, a)
2824
evState = runState mempty
2925

30-
evEff :: Sem (Eff.IdP ': r) a -> Sem (State IS ': r) a
31-
evEff = reinterpret @_ @(State IS) $ \case
26+
evEff :: Sem (Eff.IdP ': r) a -> Sem (State TypedState ': r) a
27+
evEff = reinterpret @_ @(State TypedState) $ \case
3228
Eff.StoreConfig iw ->
33-
modify' (_1 %~ storeConfig iw)
29+
modify' (storeConfig iw)
3430
Eff.GetConfig i ->
35-
gets (getConfig i . (^. _1))
31+
gets (getConfig i)
3632
Eff.GetIdByIssuerWithoutTeam iss ->
37-
gets (getIdByIssuerWithoutTeam iss . (^. _1))
33+
gets (getIdByIssuerWithoutTeam iss)
3834
Eff.GetIdByIssuerWithTeam iss team ->
39-
gets (getIdByIssuerWithTeam iss team . (^. _1))
35+
gets (getIdByIssuerWithTeam iss team)
4036
Eff.GetConfigsByTeam team ->
41-
gets (getConfigsByTeam team . (^. _1))
37+
gets (getConfigsByTeam team)
4238
Eff.DeleteConfig idp ->
43-
modify' (_1 %~ deleteConfig idp)
39+
modify' (deleteConfig idp)
4440
Eff.SetReplacedBy (Eff.Replaced replaced) (Eff.Replacing replacing) ->
45-
modify' (_1 %~ ((updateReplacedBy (Just replacing) replaced) <$>))
41+
modify' (updateReplacedBy (Just replacing) replaced <$>)
4642
Eff.ClearReplacedBy (Eff.Replaced replaced) ->
47-
modify' (_1 %~ ((updateReplacedBy Nothing replaced) <$>))
48-
Eff.StoreRawMetadata i txt ->
49-
modify (_2 %~ storeRawMetadata i txt)
50-
Eff.GetRawMetadata i ->
51-
gets (getRawMetadata i . (^. _2))
52-
Eff.DeleteRawMetadata i ->
53-
modify (_2 %~ deleteRawMetadata i)
43+
modify' (updateReplacedBy Nothing replaced <$>)
5444

5545
storeConfig :: IP.IdP -> TypedState -> TypedState
5646
storeConfig iw =
@@ -107,12 +97,3 @@ updateReplacedBy mbReplacing replaced idp =
10797
& if idp ^. SAML.idpId == replaced
10898
then SAML.idpExtraInfo . IP.wiReplacedBy .~ mbReplacing
10999
else id
110-
111-
storeRawMetadata :: SAML.IdPId -> Text -> RawState -> RawState
112-
storeRawMetadata = M.insert
113-
114-
getRawMetadata :: SAML.IdPId -> RawState -> Maybe Text
115-
getRawMetadata = M.lookup
116-
117-
deleteRawMetadata :: SAML.IdPId -> RawState -> RawState
118-
deleteRawMetadata idpid = M.filterWithKey (\idpid' _ -> idpid' /= idpid)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Spar.Sem.IdPRawMetadataStore where
2+
3+
import Imports
4+
import Polysemy
5+
import qualified SAML2.WebSSO as SAML
6+
7+
data IdPRawMetadataStore m a where
8+
Store :: SAML.IdPId -> Text -> IdPRawMetadataStore m ()
9+
Get :: SAML.IdPId -> IdPRawMetadataStore m (Maybe Text)
10+
Delete :: SAML.IdPId -> IdPRawMetadataStore m ()
11+
12+
deriving stock instance Show (IdPRawMetadataStore m a)
13+
14+
-- TODO(sandy): Inline this definition --- no TH
15+
makeSem ''IdPRawMetadataStore
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module Spar.Sem.IdPRawMetadataStore.Cassandra where
2+
3+
import Cassandra
4+
import Imports
5+
import Polysemy
6+
import qualified Spar.Data as Data
7+
import Spar.Sem.IdPRawMetadataStore
8+
9+
idpRawMetadataStoreToCassandra ::
10+
forall m r a.
11+
(MonadClient m, Member (Embed m) r) =>
12+
Sem (IdPRawMetadataStore ': r) a ->
13+
Sem r a
14+
idpRawMetadataStoreToCassandra =
15+
interpret $
16+
embed @m . \case
17+
Store i t -> Data.storeIdPRawMetadata i t
18+
Get i -> Data.getIdPRawMetadata i
19+
Delete i -> Data.deleteIdPRawMetadata i
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-}
2+
3+
module Spar.Sem.IdPRawMetadataStore.Mem (idpRawMetadataStoreToMem, RawState) where
4+
5+
import qualified Data.Map as M
6+
import Imports
7+
import Polysemy
8+
import Polysemy.State (State, gets, modify, runState)
9+
import qualified SAML2.WebSSO.Types as SAML
10+
import Spar.Sem.IdPRawMetadataStore
11+
12+
type RawState = Map SAML.IdPId Text
13+
14+
idpRawMetadataStoreToMem ::
15+
forall r a.
16+
Sem (IdPRawMetadataStore ': r) a ->
17+
Sem r (RawState, a)
18+
idpRawMetadataStoreToMem = runState mempty . evEff
19+
where
20+
evEff :: Sem (IdPRawMetadataStore ': r) a -> Sem (State RawState ': r) a
21+
evEff = reinterpret @_ @(State RawState) $ \case
22+
Store i txt ->
23+
modify $ M.insert i txt
24+
Get i ->
25+
gets $ M.lookup i
26+
Delete idpid ->
27+
modify $ M.filterWithKey (\idpid' _ -> idpid' /= idpid)

0 commit comments

Comments
 (0)