Skip to content

Commit

Permalink
fix: secures the user response from the me auth route (#3409)
Browse files Browse the repository at this point in the history
  • Loading branch information
JarrodMFlesch authored Oct 3, 2023
1 parent 9fa4a8f commit 26939a3
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 13 deletions.
17 changes: 13 additions & 4 deletions src/auth/operations/me.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import url from 'url';
import jwt from 'jsonwebtoken';
import { PayloadRequest } from '../../express/types';
import getExtractJWT from '../getExtractJWT';
Expand Down Expand Up @@ -26,16 +27,24 @@ async function me({
};

if (req.user) {
const user = { ...req.user };
const parsedURL = url.parse(req.originalUrl);
const isGraphQL = parsedURL.pathname === `/api${req.payload.config.routes.graphQL}`;

if (user.collection !== collection.config.slug) {
const user = await req.payload.findByID({
id: req.user.id,
collection: collection.config.slug,
req,
depth: isGraphQL ? 0 : collection.config.auth.depth,
overrideAccess: false,
showHiddenFields: false,
}) as User;

if (req.user.collection !== collection.config.slug) {
return {
user: null,
};
}

delete user.collection;

response = {
user,
collection: req.user.collection,
Expand Down
4 changes: 2 additions & 2 deletions src/auth/strategies/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export default ({ secret, config, collections }: Payload): PassportStrategy => {
try {
const collection = collections[token.collection];

const parsedURL = url.parse(req.url);
const isGraphQL = parsedURL.pathname === config.routes.graphQL;
const parsedURL = url.parse(req.originalUrl);
const isGraphQL = parsedURL.pathname === `/api${req.payload.config.routes.graphQL}`;

const user = await req.payload.findByID({
id: token.id,
Expand Down
9 changes: 9 additions & 0 deletions test/auth/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ export default buildConfigWithDefaults({
},
},
fields: [
{
name: 'adminOnlyField',
type: 'text',
access: {
read: ({ req: { user: { roles = [] } } }) => {
return roles.includes('admin');
},
},
},
{
name: 'roles',
label: 'Role',
Expand Down
45 changes: 45 additions & 0 deletions test/auth/int.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,51 @@ describe('Auth', () => {

expect(result).toBeTruthy();
});


it('should enforce access control on the me route', async () => {
const user = await payload.create({
collection: slug,
data: {
email: 'insecure@me.com',
password: 'test',
roles: ['admin'],
adminOnlyField: 'admin secret',
},
});

const response = await fetch(`${apiUrl}/${slug}/login`, {
body: JSON.stringify({
email: 'insecure@me.com',
password: 'test',
}),
headers,
method: 'post',
});

const data = await response.json();
const adminMe = await fetch(`${apiUrl}/${slug}/me`, {
headers: {
Authorization: `JWT ${data.token}`,
},
}).then((res) => res.json());
expect(adminMe.user.adminOnlyField).toEqual('admin secret');

await payload.update({
collection: slug,
id: user?.id || '',
data: {
roles: ['editor'],
},
});

const editorMe = await fetch(`${apiUrl}/${slug}/me`, {
headers: {
Authorization: `JWT ${adminMe?.token}`,
},
}).then((res) => res.json());
expect(editorMe.user.adminOnlyField).toBeUndefined();
});
});

describe('API Key', () => {
Expand Down
47 changes: 40 additions & 7 deletions test/auth/payload-types.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,59 @@
/* tslint:disable */
/* eslint-disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/

export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface Config {
collections: {
users: User;
'api-keys': ApiKey;
};
globals: {};
}
export interface User {
id: string;
adminOnlyField?: string;
roles: ('admin' | 'editor' | 'moderator' | 'user' | 'viewer')[];
namedSaveToJWT?: string;
group?: {
liftedSaveToJWT?: string;
};
groupSaveToJWT?: {
saveToJWTString?: string;
saveToJWTFalse?: string;
};
saveToJWTTab: {
test?: string;
};
tabSaveToJWTString: {
includedByDefault?: string;
};
tabLiftedSaveToJWT?: string;
unnamedTabSaveToJWTString?: string;
unnamedTabSaveToJWTFalse?: string;
custom?: string;
updatedAt: string;
createdAt: string;
enableAPIKey?: boolean;
apiKey?: string;
apiKeyIndex?: string;
email?: string;
email: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
salt?: string;
hash?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
password?: string;
}
export interface ApiKey {
id: string;
updatedAt: string;
createdAt: string;
enableAPIKey?: boolean;
apiKey?: string;
apiKeyIndex?: string;
}

0 comments on commit 26939a3

Please sign in to comment.