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
159
Issues
159
List
Board
Labels
Milestones
Merge Requests
8
Merge Requests
8
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
e7ad54d4
Verified
Commit
e7ad54d4
authored
May 25, 2024
by
Przemyslaw Kaminski
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[ws] implement jwt token authorization
parent
200f3b52
Pipeline
#6140
failed with stages
in 82 minutes and 23 seconds
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
57 additions
and
14 deletions
+57
-14
Types.hs
src/Gargantext/API/Admin/Auth/Types.hs
+1
-1
Settings.hs
src/Gargantext/API/Admin/Settings.hs
+1
-1
Dispatcher.hs
src/Gargantext/Core/AsyncUpdates/Dispatcher.hs
+55
-12
No files found.
src/Gargantext/API/Admin/Auth/Types.hs
View file @
e7ad54d4
...
@@ -48,7 +48,7 @@ data CheckAuth = InvalidUser | InvalidPassword | Valid Token TreeId UserId
...
@@ -48,7 +48,7 @@ data CheckAuth = InvalidUser | InvalidPassword | Valid Token TreeId UserId
data
AuthenticatedUser
=
AuthenticatedUser
data
AuthenticatedUser
=
AuthenticatedUser
{
_auth_node_id
::
NodeId
{
_auth_node_id
::
NodeId
,
_auth_user_id
::
UserId
,
_auth_user_id
::
UserId
}
deriving
(
Generic
)
}
deriving
(
Generic
,
Show
,
Eq
)
makeLenses
''
A
uthenticatedUser
makeLenses
''
A
uthenticatedUser
...
...
src/Gargantext/API/Admin/Settings.hs
View file @
e7ad54d4
...
@@ -205,7 +205,7 @@ newEnv logger port file = do
...
@@ -205,7 +205,7 @@ newEnv logger port file = do
!
central_exchange
<-
forkIO
CE
.
gServer
!
central_exchange
<-
forkIO
CE
.
gServer
!
dispatcher
<-
D
.
dispatcher
!
dispatcher
<-
D
.
dispatcher
settings'
{- An 'Env' by default doesn't have strict fields, but when constructing one in production
{- An 'Env' by default doesn't have strict fields, but when constructing one in production
we want to force them to WHNF to avoid accumulating unnecessary thunks.
we want to force them to WHNF to avoid accumulating unnecessary thunks.
...
...
src/Gargantext/Core/AsyncUpdates/Dispatcher.hs
View file @
e7ad54d4
...
@@ -26,6 +26,9 @@ import Data.Aeson.Types (prependFailure, typeMismatch)
...
@@ -26,6 +26,9 @@ import Data.Aeson.Types (prependFailure, typeMismatch)
import
Data.ByteString.Char8
qualified
as
C
import
Data.ByteString.Char8
qualified
as
C
import
Data.ByteString.Lazy
qualified
as
BSL
import
Data.ByteString.Lazy
qualified
as
BSL
import
Data.List
(
nubBy
)
import
Data.List
(
nubBy
)
import
Data.UUID.V4
as
UUID
import
Gargantext.API.Admin.Auth.Types
(
AuthenticatedUser
(
_auth_user_id
))
import
Gargantext.API.Admin.Types
(
jwtSettings
,
Settings
,
jwtSettings
)
import
Gargantext.Core.AsyncUpdates.CentralExchange.Types
qualified
as
CETypes
import
Gargantext.Core.AsyncUpdates.CentralExchange.Types
qualified
as
CETypes
import
Gargantext.Core.Types
(
NodeId
,
UserId
)
import
Gargantext.Core.Types
(
NodeId
,
UserId
)
import
Gargantext.Prelude
import
Gargantext.Prelude
...
@@ -34,6 +37,7 @@ import Nanomsg
...
@@ -34,6 +37,7 @@ import Nanomsg
import
Network.WebSockets
qualified
as
WS
import
Network.WebSockets
qualified
as
WS
import
Servant
import
Servant
import
Servant.API.WebSocket
qualified
as
WS
import
Servant.API.WebSocket
qualified
as
WS
import
Servant.Auth.Server
(
verifyJWT
)
{-
{-
...
@@ -101,6 +105,9 @@ showSub sub =
...
@@ -101,6 +105,9 @@ showSub sub =
subKey
::
Subscription
->
ByteString
subKey
::
Subscription
->
ByteString
subKey
sub
=
wsKey
$
s_ws_key_connection
sub
subKey
sub
=
wsKey
$
s_ws_key_connection
sub
type
Token
=
Text
{-
{-
We accept requests for subscription/unsubscription via websocket.
We accept requests for subscription/unsubscription via websocket.
...
@@ -115,6 +122,8 @@ browser.
...
@@ -115,6 +122,8 @@ browser.
data
WSRequest
=
data
WSRequest
=
WSSubscribe
Topic
WSSubscribe
Topic
|
WSUnsubscribe
Topic
|
WSUnsubscribe
Topic
|
WSAuthorize
Token
|
WSDeauthorize
|
WSPing
|
WSPing
|
WSPong
|
WSPong
deriving
(
Eq
,
Show
)
deriving
(
Eq
,
Show
)
...
@@ -128,6 +137,10 @@ instance FromJSON WSRequest where
...
@@ -128,6 +137,10 @@ instance FromJSON WSRequest where
"unsubscribe"
->
do
"unsubscribe"
->
do
topic
<-
o
.:
"topic"
topic
<-
o
.:
"topic"
pure
$
WSUnsubscribe
topic
pure
$
WSUnsubscribe
topic
"authorize"
->
do
token
<-
o
.:
"token"
pure
$
WSAuthorize
token
"deauthorize"
->
pure
$
WSDeauthorize
"ping"
->
pure
WSPing
"ping"
->
pure
WSPing
"pong"
->
pure
WSPong
"pong"
->
pure
WSPong
s
->
prependFailure
"parsing request type failed, "
(
typeMismatch
"request"
s
)
s
->
prependFailure
"parsing request type failed, "
(
typeMismatch
"request"
s
)
...
@@ -139,11 +152,11 @@ data Dispatcher =
...
@@ -139,11 +152,11 @@ data Dispatcher =
}
}
dispatcher
::
IO
Dispatcher
dispatcher
::
Settings
->
IO
Dispatcher
dispatcher
=
do
dispatcher
authSettings
=
do
subscriptions
<-
newTVarIO
(
[]
::
[
Subscription
])
subscriptions
<-
newTVarIO
(
[]
::
[
Subscription
])
let
server
=
wsServer
subscriptions
let
server
=
wsServer
authSettings
subscriptions
d_ce_listener
<-
forkIO
(
ce_listener
subscriptions
)
d_ce_listener
<-
forkIO
(
ce_listener
subscriptions
)
...
@@ -181,8 +194,8 @@ removeSubscriptionsForWSKey subscriptions ws =
...
@@ -181,8 +194,8 @@ removeSubscriptionsForWSKey subscriptions ws =
type
WSAPI
=
"ws"
:>
WS
.
WebSocketPending
type
WSAPI
=
"ws"
:>
WS
.
WebSocketPending
wsServer
::
TVar
[
Subscription
]
->
Server
WSAPI
wsServer
::
Settings
->
TVar
[
Subscription
]
->
Server
WSAPI
wsServer
subscriptions
=
streamData
wsServer
authSettings
subscriptions
=
streamData
where
where
streamData
::
MonadIO
m
=>
WS
.
PendingConnection
->
m
()
streamData
::
MonadIO
m
=>
WS
.
PendingConnection
->
m
()
streamData
pc
=
do
streamData
pc
=
do
...
@@ -191,7 +204,11 @@ wsServer subscriptions = streamData
...
@@ -191,7 +204,11 @@ wsServer subscriptions = streamData
-- some unique, Sec-WebSocket-Key string. We use this to compare
-- some unique, Sec-WebSocket-Key string. We use this to compare
-- connections (WS.Connection doesn't implement an Eq instance).
-- connections (WS.Connection doesn't implement an Eq instance).
let
mKey
=
head
$
filter
(
\
(
k
,
_
)
->
k
==
"Sec-WebSocket-Key"
)
$
WS
.
requestHeaders
reqHead
let
mKey
=
head
$
filter
(
\
(
k
,
_
)
->
k
==
"Sec-WebSocket-Key"
)
$
WS
.
requestHeaders
reqHead
let
key
=
snd
$
fromMaybe
(
panicTrace
"Sec-WebSocket-Key not found!"
)
mKey
let
key'
=
snd
$
fromMaybe
(
panicTrace
"Sec-WebSocket-Key not found!"
)
mKey
-- Unfortunately, a single browsers sends the same
-- Sec-WebSocket-Key so we want to make that even more unique.
uuid
<-
liftIO
$
UUID
.
nextRandom
let
key
=
key'
<>
"-"
<>
show
uuid
putText
$
show
$
WS
.
requestHeaders
reqHead
putText
$
show
$
WS
.
requestHeaders
reqHead
c
<-
liftIO
$
WS
.
acceptRequest
pc
c
<-
liftIO
$
WS
.
acceptRequest
pc
let
ws
=
WSKeyConnection
(
key
,
c
)
let
ws
=
WSKeyConnection
(
key
,
c
)
...
@@ -206,19 +223,26 @@ wsServer subscriptions = streamData
...
@@ -206,19 +223,26 @@ wsServer subscriptions = streamData
wsLoop
ws
=
flip
finally
disconnect
$
do
wsLoop
ws
=
flip
finally
disconnect
$
do
putText
"[wsLoop] connecting"
putText
"[wsLoop] connecting"
forever
$
do
wsLoop'
CUPublic
where
wsLoop'
user
=
do
dm
<-
WS
.
receiveDataMessage
(
wsConn
ws
)
dm
<-
WS
.
receiveDataMessage
(
wsConn
ws
)
case
dm
of
newUser
<-
case
dm
of
WS
.
Text
dm'
_
->
do
WS
.
Text
dm'
_
->
do
case
Aeson
.
decode
dm'
of
case
Aeson
.
decode
dm'
of
Nothing
->
putText
"[wsLoop] unknown message"
Nothing
->
do
putText
"[wsLoop] unknown message"
return
user
Just
(
WSSubscribe
topic
)
->
do
Just
(
WSSubscribe
topic
)
->
do
-- TODO Fix s_connected_user based on header
-- TODO Fix s_connected_user based on header
let
sub
=
Subscription
{
s_connected_user
=
CUPublic
let
sub
=
Subscription
{
s_connected_user
=
user
,
s_ws_key_connection
=
ws
,
s_ws_key_connection
=
ws
,
s_topic
=
topic
}
,
s_topic
=
topic
}
ss
<-
insertSubscription
subscriptions
sub
ss
<-
insertSubscription
subscriptions
sub
putText
$
"[wsLoop] subscriptions: "
<>
show
(
showSub
<$>
ss
)
putText
$
"[wsLoop] subscriptions: "
<>
show
(
showSub
<$>
ss
)
return
user
Just
(
WSUnsubscribe
topic
)
->
do
Just
(
WSUnsubscribe
topic
)
->
do
-- TODO Fix s_connected_user based on header
-- TODO Fix s_connected_user based on header
let
sub
=
Subscription
{
s_connected_user
=
CUPublic
let
sub
=
Subscription
{
s_connected_user
=
CUPublic
...
@@ -226,12 +250,31 @@ wsServer subscriptions = streamData
...
@@ -226,12 +250,31 @@ wsServer subscriptions = streamData
,
s_topic
=
topic
}
,
s_topic
=
topic
}
ss
<-
removeSubscription
subscriptions
sub
ss
<-
removeSubscription
subscriptions
sub
putText
$
"[wsLoop] subscriptions: "
<>
show
(
showSub
<$>
ss
)
putText
$
"[wsLoop] subscriptions: "
<>
show
(
showSub
<$>
ss
)
return
user
Just
(
WSAuthorize
token
)
->
do
let
jwtS
=
authSettings
^.
jwtSettings
mUser
<-
liftBase
$
verifyJWT
jwtS
(
encodeUtf8
token
)
putText
$
"[wsLoop] authorized user: "
<>
show
mUser
-- TODO Update my subscriptions!
return
$
fromMaybe
user
(
CUUser
.
_auth_user_id
<$>
mUser
)
Just
WSDeauthorize
->
do
-- TODO Update my subscriptions!
pure
CUPublic
Just
WSPing
->
do
Just
WSPing
->
do
WS
.
sendDataMessage
(
wsConn
ws
)
(
WS
.
Text
(
Aeson
.
encode
Pong
)
Nothing
)
WS
.
sendDataMessage
(
wsConn
ws
)
(
WS
.
Text
(
Aeson
.
encode
Pong
)
Nothing
)
return
user
Just
WSPong
->
do
Just
WSPong
->
do
putText
$
"[wsLoop] pong received"
putText
$
"[wsLoop] pong received"
_
->
putText
"[wsLoop] binary ws messages not supported"
return
user
where
_
->
do
putText
"[wsLoop] binary ws messages not supported"
return
user
wsLoop'
newUser
disconnect
=
do
disconnect
=
do
putText
"[wsLoop] disconnecting..."
putText
"[wsLoop] disconnecting..."
ss
<-
removeSubscriptionsForWSKey
subscriptions
ws
ss
<-
removeSubscriptionsForWSKey
subscriptions
ws
...
...
Przemyslaw Kaminski
@cgenie
mentioned in commit
5660aec0
·
Oct 08, 2024
mentioned in commit
5660aec0
mentioned in commit 5660aec07ec5a0a0a5468f440092c1a8f57a864e
Toggle commit list
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