From cfb09b1f16ba5294f0f67f99ab2db0be0ab67a0e Mon Sep 17 00:00:00 2001 From: Kallesh B S Date: Thu, 10 Jul 2025 17:06:39 +0530 Subject: [PATCH] register mod --- src/auth/auth.service.ts | 95 ++++++++++++++++------------ src/filters/auth-exception.filter.ts | 46 ++++++++++++++ src/main.ts | 3 + 3 files changed, 105 insertions(+), 39 deletions(-) create mode 100644 src/filters/auth-exception.filter.ts diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 97f032c..fbbcab0 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -3,7 +3,7 @@ import { OracleDBService } from 'src/db/db.service'; import { AuthLoginDTO, MailTemplateDTO, MailTypeDTO, SendMailDTO } from './auth.dto'; import * as oracledb from 'oracledb'; import { ConfigService } from '@nestjs/config'; -import axios, { AxiosRequestConfig } from 'axios'; +import axios, { AxiosError, AxiosRequestConfig } from 'axios'; import { Request } from 'express'; import * as jwkToPem from "jwk-to-pem" import * as jwt from "jsonwebtoken" @@ -394,7 +394,7 @@ export class AuthService { let adminAccessToken = await this.getAdminAccessToken(); - console.log(`${this.USERS_URL}/${userDetails.id}/reset-password`); + // console.log(`${this.USERS_URL}/${userDetails.id}/reset-password`); const options2: AxiosRequestConfig = { @@ -465,9 +465,9 @@ export class AuthService { // throw new BadRequestException(); // } - const response: any = await this.userMaintenanceService.ValidateEmail({ P_EMAILADDR: body.P_EMAILADDR }) + const emailVerifyResponse: any = await this.userMaintenanceService.ValidateEmail({ P_EMAILADDR: body.P_EMAILADDR }) - if (Array.isArray(response) && response[0].ERRORMESG) { + if (Array.isArray(emailVerifyResponse) && emailVerifyResponse[0].ERRORMESG) { throw new BadRequestException(); } @@ -490,7 +490,7 @@ export class AuthService { ], }; - console.log(userPayload); + // console.log(userPayload); const adminAccessToken = await this.getAdminAccessToken(); @@ -504,19 +504,26 @@ export class AuthService { if (response.status === 201) { + // console.log("Assigning role : "); + + // console.log("checking validate email response : ", response); + + const uid = await this.getUserIdByEmail(body.P_EMAILADDR); let ROLE = ""; - if (Array.isArray(response) && !response[0].ERRORMESG) { - switch (response[0].SOURCE) { + if (Array.isArray(emailVerifyResponse) && !emailVerifyResponse[0].ERRORMESG) { + switch (emailVerifyResponse[0].SOURCE) { case "USCIB": ROLE = 'ua'; break; case "SP": ROLE = 'sa'; break; case "CLIENT": ROLE = 'ca'; break; } } + // console.log("Role to assign : ", ROLE); + if (!ROLE) { console.log("ERROR while giving access : "); @@ -525,6 +532,8 @@ export class AuthService { const res = await this.assignRoleToUser(uid, ROLE); + console.log("Assigning Role sussessfully "); + console.log(res); return { statusCode: 201, message: 'User registered successfully' }; @@ -545,6 +554,46 @@ export class AuthService { } } + async assignRoleToUser(userId: string, roleName: string): Promise<{ message: string }> { + try { + const token = await this.getAdminAccessToken(); + const clientId = await this.getClientUUID(); + const role = await this.getClientRole(roleName); + + const url = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users/${userId}/role-mappings/clients/${clientId}`; + + const response = await axios.post(url, [role], { + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + validateStatus: () => true, // Let us handle non-2xx statuses manually + }); + + if (response.status >= 200 && response.status < 300) { + console.log(`✅ Role "${roleName}" successfully assigned to user ${userId}.`); + return { message: "Successfully assigned to user" }; + } else { + console.error(`❌ Failed to assign role. Status: ${response.status}, Data:`, response.data); + throw new Error(`Failed to assign role "${roleName}" to user ${userId}. Status: ${response.status}`); + } + } catch (error) { + // Handle Axios errors more gracefully + if (axios.isAxiosError(error)) { + const axiosError = error as AxiosError; + console.error(`🔥 Axios error: ${axiosError.message}`); + if (axiosError.response) { + console.error(`Response status: ${axiosError.response.status}`); + console.error(`Response data:`, axiosError.response.data); + } + } else { + console.error(`🔥 Unexpected error:`, error); + } + + throw new Error(`Error assigning role "${roleName}" to user ${userId}. See logs for details.`); + } + } + async logoutUser(refreshToken: string): Promise { const url = `${this.KEYCLOAK_BASE_URL}/logout`; @@ -627,39 +676,7 @@ export class AuthService { } } - async assignRoleToUser(userId: string, roleName: string): Promise { - try { - const token = await this.getAdminAccessToken(); - const clientId = await this.getClientUUID(); - - const role = await this.getClientRole(roleName); - - const url = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users/${userId}/role-mappings/clients/${clientId}`; - - const response = await axios.post( - url, - [role], - { - headers: { - Authorization: `Bearer ${token}`, - }, - validateStatus: () => true, // To manually check status if needed - } - ); - - if (response.status >= 200 && response.status < 300) { - console.log(`✅ Role "${roleName}" successfully assigned to user ${userId}.`); - - return { message: "Successfully assigned to user" } - } else { - throw new Error(`❌ Failed to assign role. Status: ${response.status}. Data: ${JSON.stringify(response.data)}`); - } - } catch (error) { - console.error(`🔥 Error assigning role "${roleName}" to user ${userId}:`, error.message || error); - throw error; // Rethrow to allow upstream handling - } - } async getTokenFromRefreshToken(req: Request) { diff --git a/src/filters/auth-exception.filter.ts b/src/filters/auth-exception.filter.ts new file mode 100644 index 0000000..5e8792b --- /dev/null +++ b/src/filters/auth-exception.filter.ts @@ -0,0 +1,46 @@ +import { + ExceptionFilter, + Catch, + ArgumentsHost, + UnauthorizedException, +} from '@nestjs/common'; +import { Response } from 'express'; + +@Catch(UnauthorizedException) +export class AuthExceptionFilter implements ExceptionFilter { + catch(exception: UnauthorizedException, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + + const status = exception.getStatus(); + const message = exception.message || 'Unauthorized'; + + // Check if message matches specific condition + if (message.toLocaleLowerCase() === 'authentication failed') { + // Clear cookies + response.clearCookie('access_token', { + httpOnly: true, + secure: true, + sameSite: 'none', + }); + + response.clearCookie('refresh_token', { + httpOnly: true, + secure: true, + sameSite: 'none', + }); + + // Send custom response + return response.status(status).json({ + statusCode: status, + message: 'Authentication failed. Tokens cleared.', + }); + } + + // If not a match, fallback to default response + return response.status(status).json({ + statusCode: status, + message, + }); + } +} diff --git a/src/main.ts b/src/main.ts index 2b0d996..9ffeb72 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,7 @@ import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { SwaggerDocumentOptions } from '@nestjs/swagger'; import { BadRequestException } from './exceptions/badRequest.exception'; import * as cookieParser from 'cookie-parser'; +import { AuthExceptionFilter } from './filters/auth-exception.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule, { @@ -30,6 +31,8 @@ async function bootstrap() { app.use(cookieParser()); + app.useGlobalFilters(new AuthExceptionFilter()); + function extractConstraints(validationErrors: ValidationError[]) { const constraints: { [key: string]: string }[] = [];