import { ClassTransformOptions } from 'class-transformer' ; import { ValidatorOptions } from 'class-validator' ; import { Request } from 'express' ; import { Controller , Get , Query , Redirect , Req } from '@nestjs/common' ; import { validateDto } from '@fc/common' ; import { CryptographyService } from '@fc/cryptography' ; import { EidasResponse } from '@fc/eidas' ; import { EidasToOidcService , OidcToEidasService } from '@fc/eidas-oidc-mapper' ; import { EidasProviderSession } from '@fc/eidas-provider' ; import { LoggerLevelNames , LoggerService } from '@fc/logger' ; import { AcrValues } from '@fc/oidc' ; import { OidcClientConfigService , OidcClientService , OidcClientSession , } from '@fc/oidc-client' ; import { ISessionService , Session , SessionNotFoundException , } from '@fc/session' ; import { EidasBridgeIdentityDto } from '../dto/eidas-bridge-identity.dto' ; import { EidasBridgeRoutes , IDP_ID } from '../enums' ; import { EidasBridgeInvalidIdentityException } from '../exceptions' ; todo see https @ Controller ( EidasBridgeRoutes . BASE ) export class FrIdentityToEuController { constructor ( private readonly crypto , private readonly logger , private readonly oidcClientConfig , private readonly oidcClient , private readonly eidasToOidc , private readonly oidcToEidas ) { this . logger . setContext ( this . constructor . name ) ; } @ Get ( EidasBridgeRoutes . INIT_SESSION ) @ Redirect ( ) async initSession ( todo author Hugues
     *  date ticket @ Session ( 'OidcClient' ) sessionOidc ) { const { stateLength } = await this . oidcClientConfig . get ( ) ; const idpState = this . crypto . genRandomString ( stateLength ) ; await sessionOidc . set ( { idpState , idpId : IDP_ID , } ) ; const response = { statusCode : 302 , url : `${ EidasBridgeRoutes . BASE }${ EidasBridgeRoutes . REDIRECT_TO_FC_AUTORIZE }` , } ; this . logger . trace ( { method : 'GET' , name : 'EidasBridgeRoutes.INIT_SESSION' , response , route : EidasBridgeRoutes . INIT_SESSION , } ) ; return response ; } TODO see https @ Get ( EidasBridgeRoutes . REDIRECT_TO_FC_AUTORIZE ) @ Redirect ( ) async redirectToFcAuthorize ( todo author Hugues
     *  date ticket @ Session ( 'OidcClient' ) sessionOidc , @ Session ( 'EidasProvider' ) sessionEidasProvider ) { const { eidasRequest } = await sessionEidasProvider . get ( ) ; const oidcRequest = this . eidasToOidc . mapPartialRequest ( eidasRequest ) ; const { nonce , state } = await this . oidcClient . utils . buildAuthorizeParameters ( ) ; const authorizationUrl = await this . oidcClient . utils . getAuthorizeUrl ( { acr_values : oidcRequest . acr_values , nonce , idpId : IDP_ID , scope : oidcRequest . scope . join ( ' ' ) , state , } ) ; await sessionOidc . set ( { idpNonce : nonce , idpState : state , } ) ; const response = { statusCode : 302 , url : authorizationUrl } ; this . logger . trace ( { method : 'GET' , name : 'EidasBridgeRoutes.REDIRECT_TO_FC_AUTORIZE' , response , route : EidasBridgeRoutes . REDIRECT_TO_FC_AUTORIZE , } ) ; return response ; } @ Get ( EidasBridgeRoutes . REDIRECT_TO_EIDAS_RESPONSE_PROXY ) @ Redirect ( ) async redirectToEidasResponseProxy ( @ Req ( ) req , @ Query ( ) query , @ Session ( 'EidasProvider' ) sessionEidasProvider , todo author Hugues
     *  date ticket @ Session ( 'OidcClient' ) sessionOidc ) { let partialEidasResponse ; const { error , error_description } = query ; if ( error ) { this . logger . trace ( { error } , LoggerLevelNames . WARN ) ; partialEidasResponse = this . oidcToEidas . mapPartialResponseFailure ( { error , error_description , } ) ; } else { try { partialEidasResponse = await this . handleOidcCallbackAuthCode ( req , sessionOidc , sessionEidasProvider ) ; } catch ( error ) { this . logger . trace ( { error } , LoggerLevelNames . WARN ) ; partialEidasResponse = this . oidcToEidas . mapPartialResponseFailure ( error ) ; } } await sessionEidasProvider . set ( 'partialEidasResponse' , partialEidasResponse ) ; const response = { statusCode : 302 , url : '/eidas-provider/response-proxy' , } ; this . logger . trace ( { method : 'GET' , name : 'EidasBridgeRoutes.REDIRECT_TO_EIDAS_RESPONSE_PROXY' , response , route : EidasBridgeRoutes . REDIRECT_TO_EIDAS_RESPONSE_PROXY , } ) ; return response ; } private async handleOidcCallbackAuthCode ( req , sessionOidc , sessionEidasProvider ) { const session = await sessionOidc . get ( ) ; if ( ! session ) { throw new SessionNotFoundException ( 'OidcClient' ) ; } const { idpId , idpNonce , idpState } = session ; const tokenParams = { state : idpState , nonce : idpNonce , } ; const { accessToken , acr } = await this . oidcClient . getTokenFromProvider ( idpId , tokenParams , req ) ; const userInfoParams = { accessToken , idpId , } ; const identity = await this . oidcClient . getUserInfosFromProvider ( userInfoParams , req ) ; await this . validateIdentity ( identity ) ; const { requestedAttributes } = await sessionEidasProvider . get ( 'eidasRequest' ) ; const partialEidasResponse = await this . oidcToEidas . mapPartialResponseSuccess ( identity , acr as AcrValues , requestedAttributes ) ; return partialEidasResponse ; } private async validateIdentity ( identity ) { const validatorOptions = { forbidNonWhitelisted : true , forbidUnknownValues : true , whitelist : true , } ; const transformOptions = { excludeExtraneousValues : true , } ; const errors = await validateDto ( identity , EidasBridgeIdentityDto , validatorOptions , transformOptions ) ; if ( errors . length ) { throw new EidasBridgeInvalidIdentityException ( ) ; } } }