log
This commit is contained in:
@@ -16,6 +16,7 @@ export enum ApplicationErrorCode {
|
|||||||
EXTERNAL_API_REQUEST_FAILED = 'EXTERNAL_API_REQUEST_FAILED',
|
EXTERNAL_API_REQUEST_FAILED = 'EXTERNAL_API_REQUEST_FAILED',
|
||||||
FILE_GENERATION_FAILED = 'FILE_GENERATION_FAILED',
|
FILE_GENERATION_FAILED = 'FILE_GENERATION_FAILED',
|
||||||
OIDC_AUTHORIZATION_ERROR = 'OIDC_AUTHORIZATION_ERROR',
|
OIDC_AUTHORIZATION_ERROR = 'OIDC_AUTHORIZATION_ERROR',
|
||||||
|
OIDC_INTERACTION_SESSION_NOT_FOUND = 'OIDC_INTERACTION_SESSION_NOT_FOUND',
|
||||||
OIDC_PROVIDER_ERROR = 'OIDC_PROVIDER_ERROR',
|
OIDC_PROVIDER_ERROR = 'OIDC_PROVIDER_ERROR',
|
||||||
PASSWORD_RESET_EMAIL_SEND_FAILED = 'PASSWORD_RESET_EMAIL_SEND_FAILED',
|
PASSWORD_RESET_EMAIL_SEND_FAILED = 'PASSWORD_RESET_EMAIL_SEND_FAILED',
|
||||||
REGISTRATION_APPROVAL_NOTIFICATION_FAILED = 'REGISTRATION_APPROVAL_NOTIFICATION_FAILED',
|
REGISTRATION_APPROVAL_NOTIFICATION_FAILED = 'REGISTRATION_APPROVAL_NOTIFICATION_FAILED',
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import { Body, Controller, Get, Param, Post, Req, Res, UnauthorizedException } f
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import type { Interaction } from 'oidc-provider';
|
import type { Interaction } from 'oidc-provider';
|
||||||
|
import { ApplicationErrorCategory, ApplicationErrorCode } from '../application-error-log/application-error-codes';
|
||||||
|
import { ApplicationErrorLoggerService } from '../application-error-log/application-error-logger.service';
|
||||||
|
import { RequestContextService } from '../common/request-context.service';
|
||||||
import { OidcProviderService } from './oidc-provider.service';
|
import { OidcProviderService } from './oidc-provider.service';
|
||||||
|
|
||||||
@Controller('interaction')
|
@Controller('interaction')
|
||||||
@@ -9,11 +12,28 @@ export class OidcInteractionController {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly oidc: OidcProviderService,
|
private readonly oidc: OidcProviderService,
|
||||||
private readonly config: ConfigService,
|
private readonly config: ConfigService,
|
||||||
|
private readonly applicationErrorLogger: ApplicationErrorLoggerService,
|
||||||
|
private readonly requestContext: RequestContextService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get(':uid')
|
@Get(':uid')
|
||||||
async view(@Param('uid') uid: string, @Req() request: Request, @Res() response: Response) {
|
async view(@Param('uid') uid: string, @Req() request: Request, @Res() response: Response) {
|
||||||
const details = await this.oidc.interactionDetails(request, response);
|
let details: Interaction;
|
||||||
|
try {
|
||||||
|
details = await this.oidc.interactionDetails(request, response);
|
||||||
|
} catch (error) {
|
||||||
|
await this.logInteractionSessionError(error, uid, request);
|
||||||
|
response
|
||||||
|
.status(400)
|
||||||
|
.send(
|
||||||
|
this.page(
|
||||||
|
'Anmeldung abgelaufen',
|
||||||
|
'<p class="message error" role="alert">Die SSO-Anmeldung ist abgelaufen oder konnte nicht zugeordnet werden. Bitte starten Sie die Anmeldung erneut aus der Anwendung.</p>',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (details.uid !== uid) {
|
if (details.uid !== uid) {
|
||||||
response.status(400).send(this.page('Ungueltige Anfrage', '<p>Die OIDC-Interaktion ist ungueltig.</p>'));
|
response.status(400).send(this.page('Ungueltige Anfrage', '<p>Die OIDC-Interaktion ist ungueltig.</p>'));
|
||||||
return;
|
return;
|
||||||
@@ -194,4 +214,33 @@ export class OidcInteractionController {
|
|||||||
private isInvalidCredentialsError(error: unknown): boolean {
|
private isInvalidCredentialsError(error: unknown): boolean {
|
||||||
return error instanceof UnauthorizedException && error.message === 'Ungueltige Zugangsdaten.';
|
return error instanceof UnauthorizedException && error.message === 'Ungueltige Zugangsdaten.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async logInteractionSessionError(error: unknown, uid: string, request: Request): Promise<void> {
|
||||||
|
const cookieHeader = request.headers.cookie ?? '';
|
||||||
|
await this.applicationErrorLogger.log({
|
||||||
|
error,
|
||||||
|
category: ApplicationErrorCategory.OIDC,
|
||||||
|
code: ApplicationErrorCode.OIDC_INTERACTION_SESSION_NOT_FOUND,
|
||||||
|
module: 'OidcModule',
|
||||||
|
service: OidcInteractionController.name,
|
||||||
|
operation: 'viewInteraction',
|
||||||
|
requestContext: {
|
||||||
|
...this.requestContext.get(),
|
||||||
|
method: request.method,
|
||||||
|
path: request.originalUrl || request.url,
|
||||||
|
statusCode: 400,
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
uid,
|
||||||
|
hasCookieHeader: Boolean(cookieHeader),
|
||||||
|
hasInteractionCookie: /(?:^|;\s*)_interaction=/.test(cookieHeader),
|
||||||
|
forwardedProto: request.headers['x-forwarded-proto'],
|
||||||
|
forwardedHost: request.headers['x-forwarded-host'],
|
||||||
|
host: request.headers.host,
|
||||||
|
referer: request.headers.referer,
|
||||||
|
userAgent: request.headers['user-agent'],
|
||||||
|
},
|
||||||
|
handled: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,6 +285,27 @@ export class OidcProviderService implements OnModuleInit {
|
|||||||
provider.on('access_token.issued', (token) => {
|
provider.on('access_token.issued', (token) => {
|
||||||
void this.audit.record({ type: 'oidc.access_token_issued', username: token.accountId, metadata: { clientId: token.clientId } });
|
void this.audit.record({ type: 'oidc.access_token_issued', username: token.accountId, metadata: { clientId: token.clientId } });
|
||||||
});
|
});
|
||||||
|
provider.on('interaction.started', (ctx, prompt) => {
|
||||||
|
const oidcContext = ctx as {
|
||||||
|
path?: string;
|
||||||
|
oidc?: {
|
||||||
|
client?: { clientId?: string };
|
||||||
|
params?: Record<string, unknown>;
|
||||||
|
entities?: { Interaction?: { uid?: string } };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
void this.audit.record({
|
||||||
|
type: 'oidc.interaction_started',
|
||||||
|
metadata: {
|
||||||
|
prompt: typeof prompt === 'object' && prompt && 'name' in prompt ? String(prompt.name) : undefined,
|
||||||
|
path: oidcContext.path,
|
||||||
|
clientId: oidcContext.oidc?.client?.clientId ?? oidcContext.oidc?.params?.client_id,
|
||||||
|
redirectUri: oidcContext.oidc?.params?.redirect_uri,
|
||||||
|
scope: oidcContext.oidc?.params?.scope,
|
||||||
|
interactionUid: oidcContext.oidc?.entities?.Interaction?.uid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerErrorEvents(provider: Provider): void {
|
private registerErrorEvents(provider: Provider): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user