import DadosferaLogger from '@dadosfera/dadosfera-logs'; import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Inject, Param, Post, Put, Redirect, Req, } from '@nestjs/common'; import { IdentityProviderService } from './identity-provider.service'; import { RequestUser, User } from 'src/decorators/user.decorator'; import { Language } from 'src/decorators/language.decorator'; import { LanguageEnum } from 'src/utils/languages.enum'; import { PackTheMetadata } from 'src/utils/PackTheMetadata'; import { ApiOkResponse } from '@nestjs/swagger'; import { CreateIdentityProvider, IdentityProviderListResponse, IdentityProviderResponse, } from './dto/identity-provider.dto'; import { Request } from 'express'; import ErrorCodes from 'src/utils/errorCodes'; import { Authenticated, RequireModule, RequireSomePermission, } from 'src/decorators/authentication.decorator'; import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum'; @Controller('identity-providers') export class IdentityProviderController { logger: DadosferaLogger; constructor( @Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger, private identityProviderService: IdentityProviderService, ) { this.logger = dadosferaLogger.logger; } @Post() @HttpCode(HttpStatus.OK) @ApiOkResponse({ type: IdentityProviderResponse }) @Authenticated() @RequireModule('sso') @RequireSomePermission(PERMISSIONS_GROUPS.USERS.permissions.ADMIN) async addIdentityProvider( @User() user: RequestUser, @Body() body: CreateIdentityProvider, @Language() language: LanguageEnum, ) { this.logger.info('POST /identity-providers'); const metadata = PackTheMetadata({ ...user, language, }); return await this.identityProviderService.create(body, metadata); } @Get() @HttpCode(HttpStatus.OK) @ApiOkResponse({ type: IdentityProviderListResponse }) @Authenticated() @RequireModule('sso') @RequireSomePermission(PERMISSIONS_GROUPS.USERS.permissions.ADMIN) async getProviders( @User() user: RequestUser, @Language() language: LanguageEnum, ) { this.logger.info('GET identity-providers'); const metadata = PackTheMetadata({ ...user, language, }); const result = await this.identityProviderService.getList(metadata); return result; } @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @RequireModule('sso') @RequireSomePermission(PERMISSIONS_GROUPS.USERS.permissions.ADMIN) async deleteIdentityProvider( @Param('id') id: string, @User() user: RequestUser, ) { this.logger.info('DELETE /identity-providers'); const metadata = PackTheMetadata({ ...user, }); return await this.identityProviderService.deleteIdentityProvider( id, metadata, ); } @Put(':id') @HttpCode(HttpStatus.OK) @Authenticated() @RequireModule('sso') @RequireSomePermission(PERMISSIONS_GROUPS.USERS.permissions.ADMIN) async updateIdentityProviders( @Param('id') id: string, @Body() body: CreateIdentityProvider, @User() user: RequestUser, ) { this.logger.info('PUT /identity-providers'); const metadata = PackTheMetadata({ ...user, }); return await this.identityProviderService.updateIdentityProviders( id, body, metadata, ); } @Post('/callback') @HttpCode(HttpStatus.OK) async callbackIdp( @Req() req: Request, @Language() language: LanguageEnum, @Body() body: { state: string; code: string; }, ) { this.logger.info('GET /identity-providers/callback'); const { code, state } = body; if (!code) { this.logger.error('No code received from IDP'); throw new Error(ErrorCodes.IDENTITY_PROVIDER.INVALID_RESPONSE); } if (!state) { this.logger.error('No state received from IDP'); throw new Error(ErrorCodes.IDENTITY_PROVIDER.INVALID_RESPONSE); } try { const origin = req.headers['origin'] as string; this.logger.info('Header Origin: ' + origin); const lang = language.substring(0, 2) + language.substring(2).toUpperCase(); const callbackUrl = process.env.ENV !== 'prd' ? `${origin}/auth/callback` : `${origin}/${lang}/auth/callback`; this.logger.info('Callback URL: ' + callbackUrl); return await this.identityProviderService.getTokenByIdp( code, state, callbackUrl, ); } catch (error) { this.logger.error(error); throw error; } } @Get('/links') @HttpCode(HttpStatus.OK) async providerLinks(@Req() req: Request) { this.logger.info('GET /identity-providers/links'); try { const frontDomain = req.headers['origin'] as string; this.logger.info('Header Origin: ' + frontDomain); if (!frontDomain) { this.logger.info('Not found front domain'); throw new Error(ErrorCodes.IDENTITY_PROVIDER.INVALID_HEADER); } const result = await this.identityProviderService.identityProvidersLinksPerDomain( frontDomain, ); return result; } catch (error) { this.logger.error(error); throw error; } } @Get(':id') @HttpCode(HttpStatus.OK) @Redirect() async loginIdp( @Param('id') id: string, @Req() req: Request, @Language() language: LanguageEnum, ) { this.logger.info('GET /identity-providers/:id'); try { const frontDomain = (req.headers['origin'] as string) || (req.headers['referer'] as string); this.logger.info(`Front domain: ${frontDomain}`); const host = frontDomain.lastIndexOf('/') !== -1 ? frontDomain.substring(0, frontDomain.lastIndexOf('/')) : frontDomain; const lang = language.substring(0, 2) + language.substring(2).toUpperCase(); const callbackUrl = process.env.ENV !== 'prd' ? `${host}/auth/callback` : `${host}/${lang}/auth/callback`; this.logger.info('Callback URL: ' + callbackUrl); const redirectUrl = await this.identityProviderService.loginIdentityProvider( id, callbackUrl, ); this.logger.info(`Redirecting to: ${redirectUrl}`); return { url: redirectUrl, }; } catch (error) { this.logger.error(error); throw error; } } }