faloker/purify

View on GitHub
api/src/auth/auth.controller.ts

Summary

Maintainability
A
0 mins
Test Coverage
B
87%
import {
  Controller,
  Post,
  UseGuards,
  HttpStatus,
  Request,
  Get,
  Res,
  Body,
  Delete,
} from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersService } from 'src/users/users.service';
import { ChangePasswordDto } from 'src/users/dto/user.dto';
import { ConfigService } from '@nestjs/config';
import { GenericAuthGuard } from './generic-auth.guard';
import { CredentialsAuthGuard } from './credentials-auth.guard';
import {
  ApiTags,
  ApiBody,
  ApiExcludeEndpoint,
  ApiOperation,
  ApiOkResponse,
  ApiNotFoundResponse,
} from '@nestjs/swagger';
import { SamlAuthGuard } from './saml-auth.guard';

@ApiTags('auth')
@Controller('auth')
export class AuthController {
  cookiesConfig: any;

  constructor(
    private readonly authService: AuthService,
    private readonly usersService: UsersService,
    private readonly configService: ConfigService
  ) {
    this.cookiesConfig = {
      httpOnly: true,
      path: '/',
      secure: this.configService.get<string>('SECURE') === 'true',
      sameSite: 'lax',
    };
  }

  @Post()
  @ApiBody({
    description: 'Returns JWT token for authorization flow.',
    schema: {
      type: 'object',
      properties: {
        email: { type: 'string' },
        password: { type: 'string' },
      },
    },
  })
  @UseGuards(CredentialsAuthGuard)
  async login(@Request() req, @Res() response) {
    const tokens = await this.authService.generateUserTokens(req.user);

    response
      .status(200)
      .cookie('refreshToken', tokens.refreshToken, this.cookiesConfig)
      .send({ token: tokens.accessToken });
  }

  @Get('refresh_token')
  @ApiExcludeEndpoint()
  async refreshToken(@Request() req, @Res() response) {

    // If we are using TrustedHeaders then we should always login the user
    // so their permissions are synced with upstream auth server
    if (this.configService.get<string>('USE_TRUSTED_HEADER') === 'true') {
      req.user = await this.authService.validateTrustedHeaderUser(req.headers)
      return this.login(req,response)
    }

    if (req.cookies) {
      try {
        const tokens = await this.authService.refreshUserTokens(
          req.cookies.refreshToken
        );

        response
          .cookie('refreshToken', tokens.refreshToken, this.cookiesConfig)
          .send({ token: tokens.accessToken });
      } catch (err) {
        response.status(HttpStatus.UNAUTHORIZED).send({
          statusCode: HttpStatus.UNAUTHORIZED,
          message: 'Unauthorized',
        });
      }
    } else {
      response.status(HttpStatus.UNAUTHORIZED).send({
        statusCode: HttpStatus.UNAUTHORIZED,
        message: 'Unauthorized',
      });
    }
  }

  @Delete()
  @ApiExcludeEndpoint()
  @UseGuards(GenericAuthGuard)
  async logout(@Request() req, @Res() response) {
    await this.authService.removeRefreshToken(req.user);
    response.clearCookie('refreshToken', this.cookiesConfig).send('bye');
  }

  @Get('saml')
  @UseGuards(SamlAuthGuard)
  async samlLogin() {
    // placeholder to start SAML authentication flow
  }

  @Post('saml/callback')
  @UseGuards(SamlAuthGuard)
  async samlCallback(@Request() req, @Res() response) {
    const tokens = await this.authService.generateUserTokens(req.user);

    response
      .cookie('refreshToken', tokens.refreshToken, this.cookiesConfig)
      .redirect(
        `https://${this.configService.get<string>(
          'DOMAIN'
        )}/#/saml/login/${Buffer.from(tokens.accessToken).toString('base64')}`
      );
  }

  @Post('change_password')
  @ApiOperation({ summary: 'Change user password' })
  @ApiOkResponse({ description: 'Changed successfully' })
  @ApiNotFoundResponse({ description: 'No such token' })
  changePassword(@Body() changePasswordDto: ChangePasswordDto) {
    return this.usersService.changePassword(changePasswordDto);
  }
}