mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-31 13:47:02 +02:00
Added login endpoint rate limit (#2074)
* Added login rate limit * Make more pretty * Make more pretty * Fix * Remove double after all
This commit is contained in:
parent
74c5db60be
commit
1426d5be33
@ -99,6 +99,7 @@
|
|||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"errorhandler": "^1.5.1",
|
"errorhandler": "^1.5.1",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"express-rate-limit": "^6.6.0",
|
||||||
"express-session": "^1.17.1",
|
"express-session": "^1.17.1",
|
||||||
"fast-json-patch": "^3.1.0",
|
"fast-json-patch": "^3.1.0",
|
||||||
"gravatar-url": "^3.1.0",
|
"gravatar-url": "^3.1.0",
|
||||||
|
@ -179,6 +179,11 @@ export default class Controller {
|
|||||||
this.app.use(path, router);
|
this.app.use(path, router);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
useWithMiddleware(path: string, router: IRouter, middleware: any): void {
|
||||||
|
this.app.use(path, middleware, router);
|
||||||
|
}
|
||||||
|
|
||||||
get router(): any {
|
get router(): any {
|
||||||
return this.app;
|
return this.app;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import ResetPasswordController from './auth/reset-password-controller';
|
|||||||
import { SimplePasswordProvider } from './auth/simple-password-provider';
|
import { SimplePasswordProvider } from './auth/simple-password-provider';
|
||||||
import { IUnleashConfig, IUnleashServices } from '../types';
|
import { IUnleashConfig, IUnleashServices } from '../types';
|
||||||
import LogoutController from './logout';
|
import LogoutController from './logout';
|
||||||
|
import rateLimit from 'express-rate-limit';
|
||||||
|
|
||||||
const AdminApi = require('./admin-api');
|
const AdminApi = require('./admin-api');
|
||||||
const ClientApi = require('./client-api');
|
const ClientApi = require('./client-api');
|
||||||
@ -19,9 +20,15 @@ class IndexRouter extends Controller {
|
|||||||
this.use('/health', new HealthCheckController(config, services).router);
|
this.use('/health', new HealthCheckController(config, services).router);
|
||||||
this.use('/internal-backstage', new BackstageController(config).router);
|
this.use('/internal-backstage', new BackstageController(config).router);
|
||||||
this.use('/logout', new LogoutController(config, services).router);
|
this.use('/logout', new LogoutController(config, services).router);
|
||||||
this.use(
|
this.useWithMiddleware(
|
||||||
'/auth/simple',
|
'/auth/simple',
|
||||||
new SimplePasswordProvider(config, services).router,
|
new SimplePasswordProvider(config, services).router,
|
||||||
|
rateLimit({
|
||||||
|
windowMs: 1 * 60 * 1000,
|
||||||
|
max: 5,
|
||||||
|
standardHeaders: true,
|
||||||
|
legacyHeaders: false,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
this.use(
|
this.use(
|
||||||
'/auth/reset',
|
'/auth/reset',
|
||||||
|
85
src/test/e2e/api/auth/simple-password-provider.e2e.test.ts
Normal file
85
src/test/e2e/api/auth/simple-password-provider.e2e.test.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { createTestConfig } from '../../../config/test-config';
|
||||||
|
import { IUnleashConfig } from '../../../../lib/types';
|
||||||
|
import UserService from '../../../../lib/services/user-service';
|
||||||
|
import { AccessService } from '../../../../lib/services/access-service';
|
||||||
|
import { IUser } from '../../../../lib/types/user';
|
||||||
|
import { setupApp } from '../../helpers/test-helper';
|
||||||
|
import dbInit from '../../helpers/database-init';
|
||||||
|
import getLogger from '../../../fixtures/no-logger';
|
||||||
|
import { EmailService } from '../../../../lib/services/email-service';
|
||||||
|
import SessionService from '../../../../lib/services/session-service';
|
||||||
|
import { RoleName } from '../../../../lib/types/model';
|
||||||
|
import SettingService from '../../../../lib/services/setting-service';
|
||||||
|
import { GroupService } from '../../../../lib/services/group-service';
|
||||||
|
import ResetTokenService from '../../../../lib/services/reset-token-service';
|
||||||
|
|
||||||
|
let app;
|
||||||
|
let stores;
|
||||||
|
let db;
|
||||||
|
const config: IUnleashConfig = createTestConfig({
|
||||||
|
getLogger,
|
||||||
|
server: {
|
||||||
|
unleashUrl: 'http://localhost:3000',
|
||||||
|
baseUriPath: '',
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
host: 'test',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const password = 'DtUYwi&l5I1KX4@Le';
|
||||||
|
let userService: UserService;
|
||||||
|
let adminUser: IUser;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
db = await dbInit('simple_password_provider_api_serial', getLogger);
|
||||||
|
stores = db.stores;
|
||||||
|
app = await setupApp(stores);
|
||||||
|
const groupService = new GroupService(stores, config);
|
||||||
|
const accessService = new AccessService(stores, config, groupService);
|
||||||
|
const resetTokenService = new ResetTokenService(stores, config);
|
||||||
|
const emailService = new EmailService(undefined, config.getLogger);
|
||||||
|
const sessionService = new SessionService(stores, config);
|
||||||
|
const settingService = new SettingService(stores, config);
|
||||||
|
|
||||||
|
userService = new UserService(stores, config, {
|
||||||
|
accessService,
|
||||||
|
resetTokenService,
|
||||||
|
emailService,
|
||||||
|
sessionService,
|
||||||
|
settingService,
|
||||||
|
});
|
||||||
|
const adminRole = await accessService.getRootRole(RoleName.ADMIN);
|
||||||
|
adminUser = await userService.createUser({
|
||||||
|
username: 'admin@test.com',
|
||||||
|
email: 'admin@test.com',
|
||||||
|
rootRole: adminRole.id,
|
||||||
|
password: password,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
await db.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Can log in', async () => {
|
||||||
|
await app.request
|
||||||
|
.post('/auth/simple/login')
|
||||||
|
.send({
|
||||||
|
username: adminUser.username,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Gets rate limited after 5 tries', async () => {
|
||||||
|
for (let statusCode of [200, 200, 200, 200, 429]) {
|
||||||
|
await app.request
|
||||||
|
.post('/auth/simple/login')
|
||||||
|
.send({
|
||||||
|
username: adminUser.username,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
.expect(statusCode);
|
||||||
|
}
|
||||||
|
});
|
@ -3190,6 +3190,11 @@ expect@^29.0.0, expect@^29.0.1:
|
|||||||
jest-message-util "^29.0.1"
|
jest-message-util "^29.0.1"
|
||||||
jest-util "^29.0.1"
|
jest-util "^29.0.1"
|
||||||
|
|
||||||
|
express-rate-limit@^6.6.0:
|
||||||
|
version "6.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-6.6.0.tgz#3bbc2546540d327b1b0bfa9ab5f1b2c49075af98"
|
||||||
|
integrity sha512-HFN2+4ZGdkQOS8Qli4z6knmJFnw6lZed67o6b7RGplWeb1Z0s8VXaj3dUgPIdm9hrhZXTRpCTHXA0/2Eqex0vA==
|
||||||
|
|
||||||
express-session@^1.17.1:
|
express-session@^1.17.1:
|
||||||
version "1.17.2"
|
version "1.17.2"
|
||||||
resolved "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz"
|
resolved "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user