Skip to content

Commit

Permalink
wip(idp): brute force protection
Browse files Browse the repository at this point in the history
  • Loading branch information
bouassaba committed Dec 9, 2024
1 parent ca380e9 commit 653af87
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 2 deletions.
18 changes: 18 additions & 0 deletions idp/src/token/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ export async function exchange(options: TokenExchangeOptions): Promise<Token> {
throw newUserSuspendedError()
}
if (verifyPassword(options.password, user.passwordHash)) {
await resetFailedAttempts(user.id)
return newToken(user.id, user.isAdmin)
} else {
await increaseFailedAttempts(user.id)
throw newInvalidUsernameOrPasswordError()
}
} else if (options.grant_type === 'refresh_token') {
Expand Down Expand Up @@ -145,3 +147,19 @@ function newAccessTokenExpiry(): number {
now.setSeconds(now.getSeconds() + getConfig().token.accessTokenLifetime)
return Math.floor(now.getTime() / 1000)
}

async function increaseFailedAttempts(userId: string): Promise<void> {
const user = await userRepo.findById(userId)
await userRepo.update({
id: user.id,
failedAttempts: user.failedAttempts + 1,
})
}

async function resetFailedAttempts(userId: string): Promise<void> {
const user = await userRepo.findById(userId)
await userRepo.update({
id: user.id,
failedAttempts: 0,
})
}
2 changes: 2 additions & 0 deletions idp/src/user/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type User = {
emailUpdateToken?: string
emailUpdateValue?: string
picture?: string
failedAttempts: number
createTime: string
updateTime?: string
}
Expand Down Expand Up @@ -60,6 +61,7 @@ export type UpdateOptions = {
emailUpdateToken?: string
emailUpdateValue?: string
picture?: string
failedAttempts?: number
createTime?: string
updateTime?: string
}
Expand Down
7 changes: 5 additions & 2 deletions idp/src/user/repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,9 @@ class UserRepoImpl {
email_update_token = $12,
email_update_value = $13,
picture = $14,
update_time = $15
WHERE id = $16
failed_attempts = $15,
update_time = $16
WHERE id = $17
RETURNING *`,
[
entity.fullName,
Expand All @@ -212,6 +213,7 @@ class UserRepoImpl {
entity.emailUpdateToken,
entity.emailUpdateValue,
entity.picture,
entity.failedAttempts,
new Date().toISOString(),
entity.id,
],
Expand Down Expand Up @@ -265,6 +267,7 @@ class UserRepoImpl {
emailUpdateToken: row.email_update_token,
emailUpdateValue: row.email_update_value,
picture: row.picture,
failedAttempts: row.failed_attempts,
createTime: row.create_time,
updateTime: row.update_time,
}
Expand Down
2 changes: 2 additions & 0 deletions migrations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mod m20240905_000001_add_user_active_admin_fields;
mod m20240907_000001_add_user_force_change_password_field;
mod m20240913_000001_drop_segmentation_column;
mod m20241114_000001_drop_user_force_change_password_column;
mod m20241209_000001_add_user_failed_attempts_column;

#[async_trait::async_trait]
impl MigratorTrait for Migrator {
Expand All @@ -50,6 +51,7 @@ impl MigratorTrait for Migrator {
Box::new(m20240907_000001_add_user_force_change_password_field::Migration),
Box::new(m20240913_000001_drop_segmentation_column::Migration),
Box::new(m20241114_000001_drop_user_force_change_password_column::Migration),
Box::new(m20241209_000001_add_user_failed_attempts_column::Migration),
]
}
}
50 changes: 50 additions & 0 deletions migrations/src/m20241209_000001_add_user_failed_attempts_column.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2023 Anass Bouassaba.
//
// Use of this software is governed by the Business Source License
// included in the file LICENSE in the root of this repository.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the GNU Affero General Public License v3.0 only, included in the file
// AGPL-3.0-only in the root of this repository.
use sea_orm_migration::prelude::*;

use crate::models::v1::{User};

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(
&self,
manager: &SchemaManager,
) -> Result<(), DbErr> {
manager
.alter_table(
Table::alter()
.table(User::Table)
.add_column(ColumnDef::new(User::FailedAttempts).integer().not_null().default(0))
.to_owned(),
)
.await?;

Ok(())
}

async fn down(
&self,
manager: &SchemaManager,
) -> Result<(), DbErr> {
manager
.alter_table(
Table::alter()
.table(User::Table)
.drop_column(User::FailedAttempts)
.to_owned(),
)
.await?;

Ok(())
}
}
1 change: 1 addition & 0 deletions migrations/src/models/v1/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub enum User {
IsActive,
ForceChangePassword,
Picture,
FailedAttempts,
CreateTime,
UpdateTime,
}

0 comments on commit 653af87

Please sign in to comment.