Skip to content

Commit

Permalink
Get auth to actually work on graphql subscription (#1163)
Browse files Browse the repository at this point in the history
get auth to actually work on graphql subscription
  • Loading branch information
mipyykko committed Apr 12, 2023
1 parent 752469a commit 7aff924
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 66 deletions.
8 changes: 4 additions & 4 deletions backend/accessControl.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { FieldAuthorizeResolver } from "nexus/dist/plugins/fieldAuthorizePlugin"

export enum Role {
USER,
ADMIN,
ORGANIZATION, //for automated scripts, not for accounts
VISITOR,
VISITOR = 0,
USER = 1,
ADMIN = 2,
ORGANIZATION = 3, //for automated scripts, not for accounts
}

type AuthorizeFunction = <TypeName extends string, FieldName extends string>(
Expand Down
1 change: 1 addition & 0 deletions backend/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface Context extends BaseContext {
tmcClient: TmcClient
locale?: string
req: IncomingMessage
connectionParams?: Record<string, any>
}

export interface ServerContext extends BaseContext {
Expand Down
6 changes: 1 addition & 5 deletions backend/graphql/User/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {

import { User } from "@prisma/client"

import { isAdmin, Role } from "../../accessControl"
import { isAdmin } from "../../accessControl"
import { ForbiddenError, UserInputError } from "../../lib/errors"
import { buildUserSearch, convertPagination } from "../../util/db-functions"
import { notEmpty } from "../../util/notEmpty"
Expand Down Expand Up @@ -139,10 +139,6 @@ export const UserSubscriptions = extendType({
},
authorize: isAdmin,
subscribe(_, { search }, ctx) {
if (ctx.role !== Role.ADMIN) {
throw new ForbiddenError("Not authorized")
}

const queries = buildUserSearch(search) ?? []
const fieldCount = queries.length

Expand Down
55 changes: 35 additions & 20 deletions backend/middlewares/fetchUser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { plugin } from "nexus"
import { MiddlewareFn } from "nexus/dist/plugin"

import { Role } from "../accessControl"
import { Context } from "../context"
Expand All @@ -7,29 +8,43 @@ import { redisify } from "../services/redis"
import TmcClient from "../services/tmc"
import { UserInfo } from "/domain/UserInfo"

const authMiddlewareFn: MiddlewareFn = async (
root,
args,
ctx: Context,
info,
next,
) => {
if (ctx.userDetails || ctx.organization) {
return next(root, args, ctx, info)
}

const rawToken =
ctx.req?.headers?.authorization ??
(ctx.req?.headers?.["Authorization"] as string) ??
ctx.connectionParams?.authorization ??
ctx.connectionParams?.["Authorization"] // graphql websocket
// connection?

if (!rawToken) {
ctx.role = Role.VISITOR
} else if (rawToken.startsWith("Basic")) {
await setContextOrganization(ctx, rawToken)
} else {
await setContextUser(ctx, rawToken)
}

return next(root, args, ctx, info)
}

export const moocfiAuthPlugin = () =>
plugin({
name: "moocfiAuthPlugin",
onCreateFieldResolver() {
return async (root, args, ctx: Context, info, next) => {
if (ctx.userDetails || ctx.organization) {
return next(root, args, ctx, info)
}

const rawToken =
ctx.req?.headers?.authorization ??
(ctx.req?.headers?.["Authorization"] as string) // connection?

if (!rawToken) {
ctx.role = Role.VISITOR
} else if (rawToken.startsWith("Basic")) {
await setContextOrganization(ctx, rawToken)
} else {
await setContextUser(ctx, rawToken)
}

return next(root, args, ctx, info)
}
return authMiddlewareFn
},
onCreateFieldSubscribe() {
return authMiddlewareFn
},
})

Expand Down Expand Up @@ -67,7 +82,7 @@ const setContextUser = async (ctx: Context, rawToken: string) => {
ctx,
)
} catch (e) {
// console.log("error", e)
console.log("error", e)
}

ctx.tmcClient = client
Expand Down
29 changes: 29 additions & 0 deletions backend/patches/nexus+1.3.0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
diff --git a/node_modules/nexus/dist/builder.js b/node_modules/nexus/dist/builder.js
index 656750b..ed7f817 100644
--- a/node_modules/nexus/dist/builder.js
+++ b/node_modules/nexus/dist/builder.js
@@ -807,8 +807,15 @@ class SchemaBuilder {
parentTypeConfig: typeConfig,
schemaConfig: this.config,
schemaExtension: this.schemaExtension,
- }, fieldConfig.resolve), subscribe: fieldConfig.subscribe }, builderFieldConfig);
+ }, fieldConfig.resolve), subscribe: this.makeFinalResolver({
+ builder: this.builderLens,
+ fieldConfig: builderFieldConfig,
+ parentTypeConfig: typeConfig,
+ schemaConfig: this.config,
+ schemaExtension: this.schemaExtension,
+ }, fieldConfig.subscribe) }, builderFieldConfig);
}
+
makeFinalResolver(info, resolver) {
const resolveFn = resolver || graphql_1.defaultFieldResolver;
if (this.onCreateResolverFns.length) {
@@ -819,6 +826,7 @@ class SchemaBuilder {
}
return resolveFn;
}
+
buildInputObjectField(fieldConfig, typeConfig) {
var _a, _b, _c, _d;
const nonNullDefault = this.getNonNullDefault((_b = (_a = typeConfig.extensions) === null || _a === void 0 ? void 0 : _a.nexus) === null || _b === void 0 ? void 0 : _b.config, 'input');
51 changes: 23 additions & 28 deletions backend/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,34 +76,6 @@ export default async (serverContext: ServerContext) => {
const httpServer = http.createServer(app)
const schema = createSchema()

const wsServer = new WebSocketServer({
server: httpServer,
path: isProduction ? "/api" : "/",
})

const serverCleanup = useServer(
{
schema,
context: (ctx) => {
const { prisma, logger, knex, extraContext } = serverContext

return {
...ctx,
req: {
headers: {
...ctx.connectionParams, // compatibility with middleware
},
},
prisma,
logger,
knex,
...extraContext,
}
},
},
wsServer,
)

const apolloServer = new ApolloServer<ServerContext>({
schema,
plugins: [
Expand Down Expand Up @@ -134,6 +106,29 @@ export default async (serverContext: ServerContext) => {
})
await apolloServer.start()

const wsServer = new WebSocketServer({
server: httpServer,
path: isProduction ? "/api" : "/",
})

const serverCleanup = useServer(
{
schema,
context: (ctx) => {
const { prisma, logger, knex, extraContext } = serverContext

return {
...ctx,
prisma,
logger,
knex,
...extraContext,
}
},
},
wsServer,
)

useExpressMiddleware(app, apolloServer, serverContext)

return {
Expand Down
8 changes: 5 additions & 3 deletions frontend/components/Dashboard/Users/SearchForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const StyledTableContainer = styled(TableContainer)`
width: max-content;
`
const StyledFormHelperText = styled(FormHelperText)`
margin: 8px 0;
margin: 8px 0 9px 0;
`

const ResultMeta = ({
Expand Down Expand Up @@ -139,7 +139,9 @@ const SearchForm = () => {

if (meta.finished) {
return (
<FormHelperText>
<StyledFormHelperText
style={{ margin: meta.count > 0 ? "3px 0" : undefined }}
>
{t("searchFinished")}

{meta.count > 0 && (
Expand All @@ -156,7 +158,7 @@ const SearchForm = () => {
</IconButton>
</Tooltip>
)}
</FormHelperText>
</StyledFormHelperText>
)
}

Expand Down
14 changes: 11 additions & 3 deletions frontend/components/Dashboard/Users/WideGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ const WideGrid = () => {

const RenderResults = () => {
const t = useTranslator(UsersTranslations)
const { data, loading } = useContext(UserSearchContext)
const { data, loading, meta } = useContext(UserSearchContext)
const isVeryWide = useMediaQuery("(min-width: 1200px)")
const colSpan = 5 + (isVeryWide ? 1 : 0)

if (loading) {
return (
<TableBody>
Expand All @@ -114,14 +115,21 @@ const RenderResults = () => {
)
}

if (data.length < 1)
if (data.length < 1) {
if (!meta.finished) {
return null
}

return (
<TableBody>
<TableRow>
<TableCell colSpan={colSpan}>{t("noResults")}</TableCell>
<TableCell component="th" scope="row" colSpan={colSpan}>
{t("noResults")}
</TableCell>
</TableRow>
</TableBody>
)
}

return (
<TableBody>
Expand Down
9 changes: 8 additions & 1 deletion frontend/lib/with-apollo-client/get-apollo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ function create(
? new GraphQLWsLink(
createClient({
url: production ? "wss://www.mooc.fi/api" : "ws://localhost:4000",
connectionParams: () => {
const accessToken = nookies.get()["access_token"]
if (accessToken) {
return { authorization: `Bearer ${accessToken}` }
}
return {}
},
}),
)
: null
Expand Down Expand Up @@ -162,7 +169,7 @@ function create(
error: (error) => {
// ...
console.log("error", error)
// observer.error(error)
observer.error(error)
},
})
})
Expand Down
2 changes: 1 addition & 1 deletion helm/templates/shibbo/shibbo-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
{{- include "helm.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
replicas: {{ .Values.shibboTest.replicaCount }}
{{- end }}
selector:
matchLabels:
Expand Down
5 changes: 4 additions & 1 deletion helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ kafkaConsumer:
userCourseProgressRealtime:
replicaCount: 1
userPoints:
replicaCount: 10
replicaCount: 4
userPointsRealtime:
replicaCount: 1
userCoursePoints:
replicaCount: 2

shibboTest:
replicaCount: 0

email:
# controls whether the background email service should be running
enabled: true
Expand Down

0 comments on commit 7aff924

Please sign in to comment.