Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.demo
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ OTEL_LOGS_OTLP_ENDPOINT='http://localhost:4318/v1/logs'
OTEL_HEADERS_KEY=88ca6b1XXXXXXXXXXXXXXXXXXXXXXXXXXX
OTEL_LOGGER_NAME='credebl-platform-logger'
HOSTNAME='localhost'

SESSIONS_LIMIT=10
# SSO
# To add more clients, simply add comma separated values of client names
SUPPORTED_SSO_CLIENTS=CREDEBL
Expand Down
3 changes: 2 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ SCHEMA_FILE_SERVER_URL= // Please provide schema URL
SCHEMA_FILE_SERVER_TOKEN=xxxxxxxx // Please provide schema file server token for polygon

FILEUPLOAD_CACHE_TTL= //Provide file upload cache ttl

SESSIONS_LIMIT= //Provide limits of sessions
FIELD_UPLOAD_SIZE= //Provide field upload size

IS_ECOSYSTEM_ENABLE= //Set this flag to `true` to enable the ecosystem, or `false` to disable it.
Expand All @@ -180,6 +180,7 @@ HOSTNAME='localhost' # Hostname or unique identifier
# SSO
# To add more clients, simply add comma separated values of client names
SUPPORTED_SSO_CLIENTS=CREDEBL
NEXTAUTH_PROTOCOL=

# Key for agent base wallet
AGENT_API_KEY='supersecret-that-too-16chars'
Expand Down
76 changes: 72 additions & 4 deletions apps/api-gateway/src/authz/authz.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ import {
Param,
Post,
Query,
Req,
Res,
UnauthorizedException,
UseFilters
UseFilters,
UseGuards
} from '@nestjs/common';
import { AuthzService } from './authz.service';
import { CommonService } from '../../../../libs/common/src/common.service';
import { ApiBody, ApiOperation, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { ApiResponseDto } from '../dtos/apiResponse.dto';
import { UserEmailVerificationDto } from '../user/dto/create-user.dto';
import IResponseType from '@credebl/common/interfaces/response.interface';
import { ResponseMessages } from '@credebl/common/response-messages';
import { Response } from 'express';
import { Response, Request } from 'express';
import { EmailVerificationDto } from '../user/dto/email-verify.dto';
import { AuthTokenResponse } from './dtos/auth-token-res.dto';
import { LoginUserDto } from '../user/dto/login-user.dto';
Expand All @@ -30,7 +32,10 @@ import { ResetTokenPasswordDto } from './dtos/reset-token-password';
import { RefreshTokenDto } from './dtos/refresh-token.dto';
import { getDefaultClient } from '../user/utils';
import { ClientAliasValidationPipe } from './decorators/user-auth-client';

import { SessionGuard } from './guards/session.guard';
import { UserLogoutDto } from './dtos/user-logout.dto';
import { AuthGuard } from '@nestjs/passport';
import { ISessionData } from 'apps/user/interfaces/user.interface';
@Controller('auth')
@ApiTags('auth')
@UseFilters(CustomExceptionFilter)
Expand Down Expand Up @@ -139,6 +144,7 @@ export class AuthzController {
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}

/**
* Authenticates a user and returns an access token.
*
Expand Down Expand Up @@ -168,6 +174,42 @@ export class AuthzController {
}
}

/**
* Fetch session details
*
* @returns User's access token details
*/
@Get('/sessionDetails')
@UseGuards(SessionGuard)
@ApiOperation({
summary: 'Fetch session details',
description: 'Fetch session details against logged in user'
})
@ApiQuery({
name: 'sessionId',
required: false
})
@ApiResponse({ status: HttpStatus.OK, description: 'Success', type: AuthTokenResponse })
async sessionDetails(@Res() res: Response, @Req() req: Request, @Query() sessionId: ISessionData): Promise<Response> {
this.logger.debug(`in authz controller`);

let sessionDetails;
if (0 < Object.keys(sessionId).length) {
sessionDetails = await this.authzService.getSession(sessionId);
}
if (req.user) {
sessionDetails = req.user;
}

const finalResponse: IResponseType = {
statusCode: HttpStatus.OK,
message: ResponseMessages.user.success.fetchSession,
data: sessionDetails
};

return res.status(HttpStatus.OK).json(finalResponse);
}

/**
* Resets user's password.
*
Expand Down Expand Up @@ -263,4 +305,30 @@ export class AuthzController {

return res.status(HttpStatus.OK).json(finalResponse);
}

/**
* Log out user.
*
* @body LogoutUserDto
* @returns Logged out user from current session
*/
@Post('/signout')
@ApiOperation({
summary: 'Logout user',
description: 'Logout user from current session.'
})
@ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto })
@UseGuards(AuthGuard('jwt'))
@ApiBearerAuth()
@ApiBody({ type: UserLogoutDto })
async logout(@Body() logoutUserDto: UserLogoutDto, @Res() res: Response): Promise<Response> {
await this.authzService.logout(logoutUserDto);

const finalResponse: IResponseType = {
statusCode: HttpStatus.OK,
message: ResponseMessages.user.success.logout
};

return res.status(HttpStatus.OK).json(finalResponse);
}
}
24 changes: 13 additions & 11 deletions apps/api-gateway/src/authz/authz.module.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import { ClientsModule, Transport } from '@nestjs/microservices';
import { Logger, Module } from '@nestjs/common';

import { AgentService } from '../agent/agent.service';
import { AuthzController } from './authz.controller';
import { AuthzService } from './authz.service';
import { CommonConstants } from '@credebl/common/common.constant';
import { CommonModule } from '../../../../libs/common/src/common.module';
import { CommonService } from '../../../../libs/common/src/common.service';
import { ConnectionService } from '../connection/connection.service';
import { HttpModule } from '@nestjs/axios';
import { JwtStrategy } from './jwt.strategy';
import { MobileJwtStrategy } from './mobile-jwt.strategy';
import { Module } from '@nestjs/common';
import { NATSClient } from '@credebl/common/NATSClient';
import { OrganizationService } from '../organization/organization.service';
import { PassportModule } from '@nestjs/passport';
import { PrismaServiceModule } from '@credebl/prisma-service';
import { SocketGateway } from './socket.gateway';
import { SupabaseService } from '@credebl/supabase';
import { UserModule } from '../user/user.module';
import { UserRepository } from 'apps/user/repositories/user.repository';
import { UserService } from '../user/user.service';
import { VerificationService } from '../verification/verification.service';
import { getNatsOptions } from '@credebl/common/nats.config';
import { OrganizationService } from '../organization/organization.service';
import { CommonConstants } from '@credebl/common/common.constant';
import { NATSClient } from '@credebl/common/NATSClient';

@Module({
imports: [
Expand All @@ -36,7 +38,8 @@ import { NATSClient } from '@credebl/common/NATSClient';
},
CommonModule
]),
UserModule
UserModule,
PrismaServiceModule
],
providers: [
JwtStrategy,
Expand All @@ -50,12 +53,11 @@ import { NATSClient } from '@credebl/common/NATSClient';
CommonService,
UserService,
SupabaseService,
OrganizationService
],
exports: [
PassportModule,
AuthzService
OrganizationService,
UserRepository,
Logger
],
exports: [PassportModule, AuthzService],
controllers: [AuthzController]
})
export class AuthzModule { }
export class AuthzModule {}
11 changes: 11 additions & 0 deletions apps/api-gateway/src/authz/authz.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { ForgotPasswordDto } from './dtos/forgot-password.dto';
import { ResetTokenPasswordDto } from './dtos/reset-token-password';
import { NATSClient } from '@credebl/common/NATSClient';
import { user } from '@prisma/client';
import { ISessionDetails } from 'apps/user/interfaces/user.interface';
import { UserLogoutDto } from './dtos/user-logout.dto';
@Injectable()
@WebSocketGateway()
export class AuthzService extends BaseService {
Expand Down Expand Up @@ -53,6 +55,11 @@ export class AuthzService extends BaseService {
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'user-holder-login', payload);
}

async getSession(sessionId): Promise<ISessionDetails> {
const payload = { ...sessionId };
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'fetch-session-details', payload);
}

async resetPassword(resetPasswordDto: ResetPasswordDto): Promise<IResetPasswordResponse> {
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'user-reset-password', resetPasswordDto);
}
Expand All @@ -73,4 +80,8 @@ export class AuthzService extends BaseService {
const payload = { userInfo };
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'add-user', payload);
}

async logout(logoutUserDto: UserLogoutDto): Promise<string> {
return this.natsClient.sendNatsMessage(this.authServiceProxy, 'user-logout', logoutUserDto);
}
}
15 changes: 15 additions & 0 deletions apps/api-gateway/src/authz/dtos/user-logout.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { IsArray, IsNotEmpty, IsOptional, IsString } from 'class-validator';

import { ApiPropertyOptional } from '@nestjs/swagger';

export class UserLogoutDto {
@ApiPropertyOptional({
description: 'List of session IDs to log out',
type: [String]
})
@IsOptional()
@IsArray({ message: 'sessions must be an array' })
@IsString({ each: true, message: 'each session Id must be a string' })
@IsNotEmpty({ each: true, message: 'session Id must not be empty' })
sessions?: string[];
}
27 changes: 27 additions & 0 deletions apps/api-gateway/src/authz/guards/session.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';

import { Request } from 'express';
import { UserRepository } from 'apps/user/repositories/user.repository';

@Injectable()
export class SessionGuard implements CanActivate {
constructor(private userRepository: UserRepository) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>();
const sessionId = request.cookies['session_id'];

// if (!sessionId) {
// throw new UnauthorizedException('Missing session cookie');
// }
if (sessionId) {
const user = await this.userRepository.validateSession(sessionId);
request.user = user;
}

// if (!user) {
// throw new UnauthorizedException('Invalid session');
// }
return true;
}
}
3 changes: 2 additions & 1 deletion apps/api-gateway/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as express from 'express';

import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { Logger, VERSION_NEUTRAL, VersioningType } from '@nestjs/common';

import * as cookieParser from 'cookie-parser';
import { AppModule } from './app.module';
import { HttpAdapterHost, NestFactory, Reflector } from '@nestjs/core';
import { AllExceptionsFilter } from '@credebl/common/exception-handler';
Expand Down Expand Up @@ -45,6 +45,7 @@ async function bootstrap(): Promise<void> {
expressApp.set('x-powered-by', false);
app.use(express.json({ limit: '100mb' }));
app.use(express.urlencoded({ limit: '100mb', extended: true }));
app.use(cookieParser());

app.use((req, res, next) => {
let err = null;
Expand Down
7 changes: 7 additions & 0 deletions apps/api-gateway/src/organization/organization.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,18 @@ export class OrganizationController {
}

const orgCredentials = await this.organizationService.clientLoginCredentials(clientCredentialsDto);

const finalResponse: IResponse = {
statusCode: HttpStatus.OK,
message: ResponseMessages.organisation.success.clientCredentials,
data: orgCredentials
};
res.cookie('session_id', orgCredentials.sessionId, {
httpOnly: true,
sameSite: 'none',
secure: 'http' !== process.env.NEXTAUTH_PROTOCOL
});

return res.status(HttpStatus.OK).json(finalResponse);
}
/**
Expand Down
24 changes: 23 additions & 1 deletion apps/organization/repositories/organization.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,29 @@ export class OrganizationRepository {
throw error;
}
}

async getOrgAndOwnerUser(orgId: string): Promise<user_org_roles> {
try {
return this.prisma.user_org_roles.findFirst({
where: {
orgId,
orgRole: {
name: 'owner'
}
},
include: {
user: {
select: {
id: true,
keycloakUserId: true
}
}
}
});
} catch (error) {
this.logger.error(`Error in fetch in organization with admin details`);
throw error;
}
}
async getCredDefByOrg(orgId: string): Promise<
{
tag: string;
Expand Down
Loading