Przeglądaj źródła

update accessTokenParser

Yuki Takei 10 miesięcy temu
rodzic
commit
dc1899e7d9

+ 56 - 0
apps/app/src/server/middlewares/access-token-parser/access-token-parser.integ.ts

@@ -132,4 +132,60 @@ describe('access-token-parser middleware', () => {
     expect(nextMock).toHaveBeenCalled();
   });
 
+  it('should set req.user with a valid Bearer token in Authorization header', async() => {
+    // arrange
+    const reqMock = mock<AccessTokenParserReq>({
+      user: undefined,
+      headers: {
+        authorization: undefined,
+      },
+    });
+    const resMock = mock<Response>();
+    const nextMock = vi.fn();
+
+    expect(reqMock.user).toBeUndefined();
+
+    // prepare a user with an access token
+    const targetUser = await User.create({
+      name: faker.person.fullName(),
+      username: faker.string.uuid(),
+      password: faker.internet.password(),
+      lang: 'en_US',
+      apiToken: faker.internet.password(),
+    });
+
+    // act
+    reqMock.headers.authorization = `Bearer ${targetUser.apiToken}`;
+    await accessTokenParser(reqMock, resMock, nextMock);
+
+    // assert
+    expect(reqMock.user).toBeDefined();
+    expect(reqMock.user?._id).toStrictEqual(targetUser._id);
+    expect(serializeUserSecurely).toHaveBeenCalledOnce();
+    expect(nextMock).toHaveBeenCalled();
+  });
+
+  it('should ignore non-Bearer Authorization header', async() => {
+    // arrange
+    const reqMock = mock<AccessTokenParserReq>({
+      user: undefined,
+      headers: {
+        authorization: undefined,
+      },
+    });
+    const resMock = mock<Response>();
+    const nextMock = vi.fn();
+
+    expect(reqMock.user).toBeUndefined();
+
+    // act
+    reqMock.headers.authorization = 'Basic dXNlcjpwYXNz'; // Basic auth header
+    await accessTokenParser(reqMock, resMock, nextMock);
+
+    // assert
+    expect(reqMock.user).toBeUndefined();
+    expect(serializeUserSecurely).not.toHaveBeenCalled();
+    expect(nextMock).toHaveBeenCalled();
+  });
+
 });

+ 18 - 2
apps/app/src/server/middlewares/access-token-parser/access-token-parser.ts

@@ -11,9 +11,25 @@ import type { AccessTokenParserReq } from './interfaces';
 const logger = loggerFactory('growi:middleware:access-token-parser');
 
 
+const extractBearerToken = (authHeader: string | undefined): string | null => {
+  if (authHeader == null) {
+    return null;
+  }
+
+  if (!authHeader.startsWith('Bearer ')) {
+    return null;
+  }
+
+  return authHeader.substring(7); // Remove 'Bearer ' prefix
+};
+
 export const accessTokenParser = async(req: AccessTokenParserReq, res: Response, next: NextFunction): Promise<void> => {
-  // TODO: comply HTTP header of RFC6750 / Authorization: Bearer
-  const accessToken = req.query.access_token ?? req.body.access_token;
+  // Extract token from Authorization header first
+  const bearerToken = extractBearerToken(req.headers.authorization);
+
+  // Try all possible token sources in order of priority
+  const accessToken = bearerToken ?? req.query.access_token ?? req.body.access_token;
+
   if (accessToken == null || typeof accessToken !== 'string') {
     return next();
   }