Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
haskell-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
157
Issues
157
List
Board
Labels
Milestones
Merge Requests
9
Merge Requests
9
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
haskell-gargantext
Commits
2cf2292e
Commit
2cf2292e
authored
Oct 28, 2024
by
Alfredo Di Napoli
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Introduce correct policy check for the Move API
parent
3d91bc98
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
44 additions
and
12 deletions
+44
-12
PolicyCheck.hs
src/Gargantext/API/Auth/PolicyCheck.hs
+15
-3
Node.hs
src/Gargantext/API/Node.hs
+5
-3
Node.hs
src/Gargantext/API/Routes/Named/Node.hs
+4
-2
Prelude.hs
test/Test/API/Prelude.hs
+16
-0
Move.hs
test/Test/API/Private/Move.hs
+4
-4
No files found.
src/Gargantext/API/Auth/PolicyCheck.hs
View file @
2cf2292e
...
...
@@ -16,6 +16,7 @@ module Gargantext.API.Auth.PolicyCheck (
,
nodeSuper
,
nodeUser
,
nodeChecks
,
moveChecks
,
userMe
,
alwaysAllow
,
alwaysDeny
...
...
@@ -42,6 +43,7 @@ import Servant.Ekg (HasEndpoint(..))
import
Servant.Server.Internal.Delayed
(
addParameterCheck
)
import
Servant.Server.Internal.DelayedIO
(
DelayedIO
(
..
))
import
Servant.Swagger
qualified
as
Swagger
import
Gargantext.Database.Query.Table.NodeNode
-------------------------------------------------------------------------------
-- Types
...
...
@@ -169,6 +171,15 @@ nodeShared = BConst . Positive . AC_node_shared
nodeChecks
::
NodeId
->
BoolExpr
AccessCheck
nodeChecks
nid
=
nodeUser
nid
`
BOr
`
nodeSuper
nid
`
BOr
`
nodeDescendant
nid
`
BOr
`
nodeShared
nid
-- | A user can move a node from source to target only
-- if:
-- * He/she is a super user
-- * He/she owns the target or the source
moveChecks
::
SourceId
->
TargetId
->
BoolExpr
AccessCheck
moveChecks
(
SourceId
sourceId
)
(
TargetId
targetId
)
=
BAnd
(
nodeUser
sourceId
`
BOr
`
nodeSuper
sourceId
)
(
nodeUser
targetId
`
BOr
`
nodeUser
targetId
)
alwaysAllow
::
BoolExpr
AccessCheck
alwaysAllow
=
BConst
.
Positive
$
AC_always_allow
...
...
@@ -200,10 +211,11 @@ instance HasEndpoint sub => HasEndpoint (PolicyChecked sub) where
enumerateEndpoints
_
=
enumerateEndpoints
(
Proxy
::
Proxy
sub
)
instance
HasClient
m
sub
=>
HasClient
m
(
PolicyChecked
sub
)
where
type
Client
m
(
PolicyChecked
sub
)
=
AccessPolicyManager
->
Client
m
sub
clientWithRoute
m
_
req
_mgr
=
clientWithRoute
m
(
Proxy
::
Proxy
sub
)
req
-- Clients don't need to be aware of the AccessPolicyManager
type
Client
m
(
PolicyChecked
sub
)
=
Client
m
sub
clientWithRoute
m
_
req
=
clientWithRoute
m
(
Proxy
::
Proxy
sub
)
req
hoistClientMonad
pm
_
nt
cl
=
hoistClientMonad
pm
(
Proxy
::
Proxy
sub
)
nt
.
cl
hoistClientMonad
pm
_
nt
cl
=
hoistClientMonad
pm
(
Proxy
::
Proxy
sub
)
nt
$
cl
instance
(
HasRoutes
subApi
)
=>
HasRoutes
(
PolicyChecked
subApi
)
where
getRoutes
=
...
...
src/Gargantext/API/Node.hs
View file @
2cf2292e
...
...
@@ -28,10 +28,10 @@ Node API
module
Gargantext.API.Node
where
import
Gargantext.API.Admin.Auth
(
withNamedAccess
,
withNamedPolicyT
)
import
Gargantext.API.Admin.Auth
(
withNamedAccess
,
withNamedPolicyT
,
withPolicy
)
import
Gargantext.API.Admin.Auth.Types
(
PathId
(
..
),
AuthenticatedUser
(
..
),
auth_node_id
,
auth_user_id
)
import
Gargantext.API.Admin.EnvTypes
(
Env
)
import
Gargantext.API.Auth.PolicyCheck
(
nodeChecks
,
AccessPolicyManager
)
import
Gargantext.API.Auth.PolicyCheck
(
nodeChecks
,
moveChecks
,
AccessPolicyManager
)
import
Gargantext.API.Errors.Types
(
BackendInternalError
)
import
Gargantext.API.Metrics
import
Gargantext.API.Ngrams.Types
(
TabType
(
..
))
...
...
@@ -253,7 +253,9 @@ genericNodeAPI' _ authenticatedUser targetNode = Named.NodeAPI
,
pieAPI
=
pieApi
targetNode
,
treeAPI
=
treeApi
targetNode
,
phyloAPI
=
phyloAPI
targetNode
,
moveAPI
=
Named
.
MoveAPI
$
moveNode
loggedInUserId
targetNode
,
moveAPI
=
Named
.
MoveAPI
$
\
parentId
->
withPolicy
authenticatedUser
(
moveChecks
(
SourceId
targetNode
)
(
TargetId
parentId
))
$
moveNode
loggedInUserId
targetNode
parentId
,
unpublishEp
=
Share
.
unPublish
targetNode
,
fileAPI
=
Named
.
FileAPI
$
fileApi
targetNode
,
fileAsyncAPI
=
fileAsyncApi
authenticatedUser
targetNode
...
...
src/Gargantext/API/Routes/Named/Node.hs
View file @
2cf2292e
...
...
@@ -91,7 +91,7 @@ data NodeAPI a mode = NodeAPI
,
pieAPI
::
mode
:-
"pie"
:>
NamedRoutes
PieAPI
,
treeAPI
::
mode
:-
"tree"
:>
NamedRoutes
TreeAPI
,
phyloAPI
::
mode
:-
"phylo"
:>
NamedRoutes
PhyloAPI
,
moveAPI
::
mode
:-
"move"
:>
NamedRoutes
MoveAPI
,
moveAPI
::
mode
:-
"move"
:>
NamedRoutes
MoveAPI
,
unpublishEp
::
mode
:-
"unpublish"
:>
NamedRoutes
Share
.
Unpublish
,
fileAPI
::
mode
:-
"file"
:>
NamedRoutes
FileAPI
,
fileAsyncAPI
::
mode
:-
"async"
:>
NamedRoutes
FileAsyncAPI
...
...
@@ -151,7 +151,9 @@ newtype UpdateAPI mode = UpdateAPI
newtype
MoveAPI
mode
=
MoveAPI
{
moveNodeEp
::
mode
:-
Summary
"Move Node endpoint"
:>
Capture
"parent_id"
ParentId
:>
Put
'[
J
SON
]
[
Int
]
{
moveNodeEp
::
mode
:-
Summary
"Move Node endpoint"
:>
Capture
"parent_id"
ParentId
:>
PolicyChecked
(
Put
'[
J
SON
]
[
Int
])
}
deriving
Generic
...
...
test/Test/API/Prelude.hs
View file @
2cf2292e
...
...
@@ -6,9 +6,11 @@ module Test.API.Prelude
,
newPublicFolderForUser
,
getRootPublicFolderIdForUser
,
checkEither
,
shouldFailWith
)
where
import
Data.Text
qualified
as
T
import
Gargantext.API.Errors
import
Gargantext.Core.Types.Individu
import
Gargantext.Core.Types
(
NodeId
)
import
Gargantext.Core.Types
(
NodeType
(
..
))
...
...
@@ -18,7 +20,11 @@ import Gargantext.Database.Query.Table.Node
import
Gargantext.Database.Query.Tree.Root
import
Gargantext.Database.Schema.Node
(
_node_id
)
import
Gargantext.Prelude
hiding
(
get
)
import
Prelude
(
fail
)
import
Servant.Client.Core
import
Test.Database.Types
import
Test.Tasty.HUnit
(
Assertion
,
(
@?=
))
import
qualified
Data.Aeson
as
JSON
checkEither
::
(
Show
a
,
Monad
m
)
=>
m
(
Either
a
b
)
->
m
b
checkEither
=
fmap
(
either
(
\
x
->
panicTrace
$
"checkEither:"
<>
T
.
pack
(
show
x
))
identity
)
...
...
@@ -50,3 +56,13 @@ newPublicFolderForUser env uname = flip runReaderT env $ runTestMonad $ do
getRootPublicFolderIdForUser
::
TestEnv
->
User
->
IO
NodeId
getRootPublicFolderIdForUser
env
uname
=
flip
runReaderT
env
$
runTestMonad
$
do
_node_id
<$>
(
getUserId
uname
>>=
getUserRootPublicNode
)
shouldFailWith
::
Show
a
=>
Either
ClientError
a
->
BackendErrorCode
->
Assertion
action
`
shouldFailWith
`
backendError
=
case
action
of
Right
{}
->
fail
"Expected action to fail, but it didn't."
Left
fr
@
(
FailureResponse
_req
res
)
|
Right
FrontendError
{
..
}
<-
JSON
.
eitherDecode
(
responseBody
res
)
->
fe_type
@?=
backendError
|
otherwise
->
fail
$
"FailureResponse didn't have FrontendError: "
<>
show
fr
_xs
->
fail
$
"Unexpected ClientError: "
<>
show
_xs
test/Test/API/Private/Move.hs
View file @
2cf2292e
...
...
@@ -17,7 +17,7 @@ import Gargantext.Database.Query.Table.NodeNode (SourceId(..), TargetId(..))
import
Gargantext.Prelude
import
Servant.Auth.Client
qualified
as
SC
import
Servant.Client
import
Test.API.Prelude
(
newCorpusForUser
,
getRootPublicFolderIdForUser
,
checkEither
)
import
Test.API.Prelude
(
newCorpusForUser
,
getRootPublicFolderIdForUser
,
checkEither
,
shouldFailWith
)
import
Test.API.Routes
import
Test.API.Setup
import
Test.Hspec
...
...
@@ -55,11 +55,11 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
it
"should forbid moving a corpus node into another user Public folder"
$
\
(
SpecContext
testEnv
serverPort
app
_
)
->
do
withApplication
app
$
do
withValidLogin
serverPort
"alice"
(
GargPassword
"alice"
)
$
\
clientEnv
token
->
do
nodes
<-
liftIO
$
do
liftIO
$
do
cId
<-
newCorpusForUser
testEnv
"alice"
bobPublicFolderId
<-
getRootPublicFolderIdForUser
testEnv
(
UserName
"bob"
)
checkEither
$
runClientM
(
moveNodeFromTo
(
toServantToken
token
)
(
SourceId
bobPublicFolderId
)
(
TargetId
cId
))
clientEnv
liftIO
$
length
nodes
`
shouldBe
`
1
res
<-
runClientM
(
moveNodeFromTo
(
toServantToken
token
)
(
SourceId
bobPublicFolderId
)
(
TargetId
cId
))
clientEnv
res
`
shouldFailWith
`
EC_500__internal_server_error
it
"should allow moving a corpus node into Alice Public folder"
$
\
(
SpecContext
testEnv
serverPort
app
_
)
->
do
withApplication
app
$
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment