security: authenticate GraphQL subscription WebSocket connections

The onConnect handler for GraphQL subscriptions was empty, allowing any
client to establish a WebSocket connection and subscribe to loggingLiveTrail
without authentication. Added JWT verification in onConnect using the same
RS256 credentials and permission checks (manage:system) used elsewhere.
pull/7922/head
kolega.dev 3 weeks ago
parent 6ae53bf1bd
commit 6f4c1da8e2

@ -114,7 +114,11 @@ const graphQLWSLink = new WebSocketLink({
uri: graphQLWSEndpoint,
options: {
reconnect: true,
lazy: true
lazy: true,
connectionParams: () => {
const token = Cookies.get('jwt')
return token ? { token } : {}
}
}
})

@ -4,6 +4,8 @@ const https = require('https')
const { ApolloServer } = require('apollo-server-express')
const Promise = require('bluebird')
const _ = require('lodash')
const jwt = require('jsonwebtoken')
const cookie = require('cookie')
/* global WIKI */
@ -125,7 +127,35 @@ module.exports = {
context: ({ req, res }) => ({ req, res }),
subscriptions: {
onConnect: (connectionParams, webSocket) => {
let token = _.get(connectionParams, 'token', null)
if (!token) {
const cookieHeader = _.get(webSocket, 'upgradeReq.headers.cookie', '')
if (cookieHeader) {
const cookies = cookie.parse(cookieHeader)
token = cookies.jwt || null
}
}
if (!token) {
throw new Error('Unauthorized')
}
try {
const user = jwt.verify(token, WIKI.config.certs.public, {
audience: WIKI.config.auth.audience,
issuer: 'urn:wiki.js',
algorithms: ['RS256']
})
if (!_.includes(user.permissions, 'manage:system')) {
throw new Error('Forbidden')
}
return { user }
} catch (err) {
throw new Error('Unauthorized')
}
},
path: '/graphql-subscriptions'
}

Loading…
Cancel
Save