Skip to content

Commit 8b856c3

Browse files
committed
fix: Endpoints /login and /verifyPassword ignore _User protectedFields
1 parent 57a4fba commit 8b856c3

File tree

2 files changed

+97
-5
lines changed

2 files changed

+97
-5
lines changed

spec/ProtectedFields.spec.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,64 @@ describe('ProtectedFields', function () {
19731973
expect(response.data.objectId).toBe(user.id);
19741974
});
19751975

1976+
it('/login respects protectedFieldsOwnerExempt: false', async function () {
1977+
await reconfigureServer({
1978+
protectedFields: {
1979+
_User: {
1980+
'*': ['phone'],
1981+
},
1982+
},
1983+
protectedFieldsOwnerExempt: false,
1984+
});
1985+
const user = await Parse.User.signUp('user1', 'password');
1986+
const sessionToken = user.getSessionToken();
1987+
user.set('phone', '555-1234');
1988+
await user.save(null, { sessionToken });
1989+
1990+
const response = await request({
1991+
method: 'POST',
1992+
url: 'http://localhost:8378/1/login',
1993+
headers: {
1994+
'X-Parse-Application-Id': 'test',
1995+
'X-Parse-REST-API-Key': 'rest',
1996+
'Content-Type': 'application/json',
1997+
},
1998+
body: JSON.stringify({ username: 'user1', password: 'password' }),
1999+
});
2000+
expect(response.data.phone).toBeUndefined();
2001+
expect(response.data.objectId).toBe(user.id);
2002+
expect(response.data.sessionToken).toBeDefined();
2003+
});
2004+
2005+
it('/verifyPassword respects protectedFieldsOwnerExempt: false', async function () {
2006+
await reconfigureServer({
2007+
protectedFields: {
2008+
_User: {
2009+
'*': ['phone'],
2010+
},
2011+
},
2012+
protectedFieldsOwnerExempt: false,
2013+
verifyUserEmails: false,
2014+
});
2015+
const user = await Parse.User.signUp('user1', 'password');
2016+
const sessionToken = user.getSessionToken();
2017+
user.set('phone', '555-1234');
2018+
await user.save(null, { sessionToken });
2019+
2020+
const response = await request({
2021+
method: 'POST',
2022+
url: 'http://localhost:8378/1/verifyPassword',
2023+
headers: {
2024+
'X-Parse-Application-Id': 'test',
2025+
'X-Parse-REST-API-Key': 'rest',
2026+
'Content-Type': 'application/json',
2027+
},
2028+
body: JSON.stringify({ username: 'user1', password: 'password' }),
2029+
});
2030+
expect(response.data.phone).toBeUndefined();
2031+
expect(response.data.objectId).toBe(user.id);
2032+
});
2033+
19762034
it('owner sees non-protected fields like email when protectedFieldsOwnerExempt is true', async function () {
19772035
await reconfigureServer({
19782036
protectedFields: {

src/Routers/UsersRouter.js

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,12 +364,30 @@ export class UsersRouter extends ClassesRouter {
364364
req.info.context
365365
);
366366

367+
// Re-fetch the user with the caller's auth context so that
368+
// protectedFields and CLP apply correctly
369+
const userAuth = new Auth.Auth({
370+
config: req.config,
371+
isMaster: false,
372+
user: Parse.Object.fromJSON({ className: '_User', objectId: user.objectId }),
373+
installationId: req.info.installationId,
374+
});
375+
const filteredUserResponse = await rest.get(
376+
req.config,
377+
userAuth,
378+
'_User',
379+
user.objectId,
380+
{},
381+
req.info.clientSDK,
382+
req.info.context
383+
);
384+
const filteredUser = filteredUserResponse.results?.[0] || user;
385+
filteredUser.sessionToken = user.sessionToken;
367386
if (authDataResponse) {
368-
user.authDataResponse = authDataResponse;
387+
filteredUser.authDataResponse = authDataResponse;
369388
}
370-
await req.config.authDataManager.runAfterFind(req, user.authData);
371389

372-
return { response: user };
390+
return { response: filteredUser };
373391
}
374392

375393
/**
@@ -436,8 +454,24 @@ export class UsersRouter extends ClassesRouter {
436454
.then(async user => {
437455
// Remove hidden properties.
438456
UsersRouter.removeHiddenProperties(user);
439-
await req.config.authDataManager.runAfterFind(req, user.authData);
440-
return { response: user };
457+
// Re-fetch the user with the caller's auth context so that
458+
// protectedFields and CLP apply correctly
459+
const userAuth = new Auth.Auth({
460+
config: req.config,
461+
isMaster: false,
462+
user: Parse.Object.fromJSON({ className: '_User', objectId: user.objectId }),
463+
installationId: req.info.installationId,
464+
});
465+
const filteredUserResponse = await rest.get(
466+
req.config,
467+
userAuth,
468+
'_User',
469+
user.objectId,
470+
{},
471+
req.info.clientSDK,
472+
req.info.context
473+
);
474+
return { response: filteredUserResponse.results?.[0] || user };
441475
})
442476
.catch(error => {
443477
throw error;

0 commit comments

Comments
 (0)