This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch x-forwarded-for in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 2a56444c68fe5a6608490c0f8c9748801f3dff65 Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Thu Dec 5 08:36:16 2024 +0100 [ENHANCEMENT] ip and x-forwarded-for im JMAP logging context --- .../java/org/apache/james/util/ReactorUtils.java | 2 +- .../jmap/method/DelegateSetCreatePerformer.scala | 19 +++--- .../jmap/method/DelegateSetDeletePerformer.scala | 18 +++--- .../method/DelegatedAccountDeletePerformer.scala | 17 +++--- .../jmap/method/EmailSetDeletePerformer.scala | 11 ++-- .../jmap/method/EmailSubmissionSetMethod.scala | 70 ++++++++++++---------- .../jmap/method/MailboxSetUpdatePerformer.scala | 23 +++---- .../apache/james/jmap/routes/JMAPApiRoutes.scala | 4 ++ 8 files changed, 95 insertions(+), 69 deletions(-) diff --git a/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java b/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java index 8c26be6382..beb2c0dc5e 100644 --- a/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java +++ b/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java @@ -194,7 +194,7 @@ public class ReactorUtils { return signal -> logWithContext(logStatement, signal.getContextView()); } - private static void logWithContext(Runnable logStatement, ContextView contextView) { + public static void logWithContext(Runnable logStatement, ContextView contextView) { try (Closeable mdc = retrieveMDCBuilder(contextView).build()) { logStatement.run(); } catch (IOException e) { diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetCreatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetCreatePerformer.scala index dd72143d0c..da3ff86305 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetCreatePerformer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetCreatePerformer.scala @@ -30,7 +30,7 @@ import org.apache.james.jmap.method.DelegateSetCreatePerformer.{CreationFailure, import org.apache.james.mailbox.MailboxSession import org.apache.james.mailbox.exception.UserDoesNotExistException import org.apache.james.user.api.{DelegationStore, UsersRepository} -import org.apache.james.util.AuditTrail +import org.apache.james.util.{AuditTrail, ReactorUtils} import org.slf4j.LoggerFactory import play.api.libs.json.JsObject import reactor.core.scala.publisher.{SFlux, SMono} @@ -98,13 +98,16 @@ class DelegateSetCreatePerformer @Inject()(delegationStore: DelegationStore, SMono.fromPublisher(usersRepository.containsReactive(request.username)) .filter(bool => bool) .flatMap(_ => SMono.fromPublisher(delegationStore.addAuthorizedUser(mailboxSession.getUser, request.username)) - .doOnSuccess(_ => AuditTrail.entry - .username(() => mailboxSession.getUser.asString()) - .protocol("JMAP") - .action("DelegateSet/create") - .parameters(() => ImmutableMap.of("delegator", mailboxSession.getUser.asString(), - "delegatee", request.username.asString())) - .log("Delegation added.")) + .subscriberContext(context => { + ReactorUtils.logWithContext(() => AuditTrail.entry + .username(() => mailboxSession.getUser.asString()) + .protocol("JMAP") + .action("DelegateSet/create") + .parameters(() => ImmutableMap.of("delegator", mailboxSession.getUser.asString(), + "delegatee", request.username.asString())) + .log("Delegation added."), context) + context + }) .`then`(SMono.just[CreationResult](CreationSuccess(delegateCreationId, evaluateCreationResponse(request, mailboxSession)))) .onErrorResume(e => SMono.just[CreationResult](CreationFailure(delegateCreationId, e)))) .switchIfEmpty(SMono.just[CreationResult](CreationFailure(delegateCreationId, new UserDoesNotExistException(request.username)))) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetDeletePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetDeletePerformer.scala index 2e7f88e4dc..cf8487366c 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetDeletePerformer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegateSetDeletePerformer.scala @@ -80,12 +80,16 @@ class DelegateSetDeletePerformer @Inject()(delegationStore: DelegationStore) { .filter(authorizedUser => DelegationId.from(baseUser, authorizedUser).equals(id)) .next() .flatMap(authorizedUser => SMono(delegationStore.removeAuthorizedUser(baseUser, authorizedUser)) - .doOnSuccess(_ => AuditTrail.entry - .username(() => baseUser.asString()) - .protocol("JMAP") - .action("DelegateSet/destroy") - .parameters(() => ImmutableMap.of("delegator", baseUser.asString(), - "delegatee", authorizedUser.asString())) - .log("Delegation removed."))) + + .subscriberContext(context => { + ReactorUtils.logWithContext(() => AuditTrail.entry + .username(() => baseUser.asString()) + .protocol("JMAP") + .action("DelegateSet/destroy") + .parameters(() => ImmutableMap.of("delegator", baseUser.asString(), + "delegatee", authorizedUser.asString())) + .log("Delegation removed."), context) + context + })) .`then`(SMono.just[DelegateDeletionResult](DelegateDeletionSuccess(id)))) } diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegatedAccountDeletePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegatedAccountDeletePerformer.scala index 677b46c492..149fceaabf 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegatedAccountDeletePerformer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/DelegatedAccountDeletePerformer.scala @@ -80,12 +80,15 @@ class DelegatedAccountDeletePerformer @Inject()(delegationStore: DelegationStore .filter(delegatedUser => DelegationId.from(delegatedUser, baseUser).equals(id)) .next() .flatMap(delegatedUser => SMono(delegationStore.removeDelegatedUser(baseUser, delegatedUser)) - .doOnSuccess(_ => AuditTrail.entry - .username(() => baseUser.asString()) - .protocol("JMAP") - .action("DelegatedAccountSet/destroy") - .parameters(() => ImmutableMap.of("delegator", delegatedUser.asString(), - "delegatee", baseUser.asString())) - .log("Delegation removed."))) + .subscriberContext(context => { + ReactorUtils.logWithContext(() => AuditTrail.entry + .username(() => baseUser.asString()) + .protocol("JMAP") + .action("DelegatedAccountSet/destroy") + .parameters(() => ImmutableMap.of("delegator", delegatedUser.asString(), + "delegatee", baseUser.asString())) + .log("Delegation removed."), context) + context + })) .`then`(SMono.just[DelegatedAccountDeletionResult](DelegatedAccountDeletionSuccess(id)))) } \ No newline at end of file diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetDeletePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetDeletePerformer.scala index b75764f300..72e8d56d18 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetDeletePerformer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetDeletePerformer.scala @@ -97,7 +97,10 @@ class EmailSetDeletePerformer @Inject()(messageIdManager: MessageIdManager, } SMono(messageIdManager.delete(messageIds.toSet.asJava, mailboxSession)) - .doOnSuccess(auditTrail(_, mailboxSession)) + .subscriberContext(context => { + auditTrail(messageIds, mailboxSession) + context + }) .map(DestroyResult.from) .onErrorResume(e => SMono.just(messageIds.map(id => DestroyFailure(EmailSet.asUnparsed(id), e)))) .map(_ ++ parsingErrors) @@ -107,13 +110,13 @@ class EmailSetDeletePerformer @Inject()(messageIdManager: MessageIdManager, } } - private def auditTrail(deleteResult: DeleteResult, mailboxSession: MailboxSession): Unit = - if (!deleteResult.getDestroyed.isEmpty) { + private def auditTrail(deleteResult: Seq[MessageId], mailboxSession: MailboxSession): Unit = + if (deleteResult.nonEmpty) { AuditTrail.entry .username(() => mailboxSession.getUser.asString()) .protocol("JMAP") .action("Email/set destroy") - .parameters(() => ImmutableMap.of("messageIds", StringUtils.join(deleteResult.getDestroyed), + .parameters(() => ImmutableMap.of("messageIds", StringUtils.join(deleteResult), "loggedInUser", mailboxSession.getLoggedInUser.toScala .map(_.asString()) .getOrElse(""))) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala index 95fa095a44..d5c5939e58 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala @@ -51,7 +51,7 @@ import org.apache.james.queue.api.MailQueueFactory.SPOOL import org.apache.james.queue.api.{MailQueue, MailQueueFactory} import org.apache.james.rrt.api.CanSendFrom import org.apache.james.server.core.{MailImpl, MimeMessageSource, MimeMessageWrapper} -import org.apache.james.util.AuditTrail +import org.apache.james.util.{AuditTrail, ReactorUtils} import org.apache.mailet.{Attribute, AttributeName, AttributeValue, Mail} import org.slf4j.{Logger, LoggerFactory} import play.api.libs.json._ @@ -298,38 +298,44 @@ class EmailSubmissionSetMethod @Inject()(serializer: EmailSubmissionSetSerialize private def enqueue(mail: Mail, delay: Duration, mailboxSession: MailboxSession): SMono[Unit] = (delay match { case d if d.isNegative || d.isZero => SMono(queue.enqueueReactive(mail)) - .doOnSuccess(_ => AuditTrail.entry - .username(() => mailboxSession.getUser.asString()) - .protocol("JMAP") - .action("EmailSubmission") - .parameters(() => ImmutableMap.of("mailId", mail.getName, - "mimeMessageId", Option(mail.getMessage) - .flatMap(message => Option(message.getMessageID)) - .getOrElse(""), - "sender", mail.getMaybeSender.asString, - "recipients", StringUtils.join(mail.getRecipients), - "size", mail.getMessageSize.toString, - "loggedInUser", mailboxSession.getLoggedInUser.toScala - .map(_.asString()) - .getOrElse(""))) - .log("JMAP mail spooled.")) + .subscriberContext(context => { + ReactorUtils.logWithContext(() => AuditTrail.entry + .username(() => mailboxSession.getUser.asString()) + .protocol("JMAP") + .action("EmailSubmission") + .parameters(() => ImmutableMap.of("mailId", mail.getName, + "mimeMessageId", Option(mail.getMessage) + .flatMap(message => Option(message.getMessageID)) + .getOrElse(""), + "sender", mail.getMaybeSender.asString, + "recipients", StringUtils.join(mail.getRecipients), + "size", mail.getMessageSize.toString, + "loggedInUser", mailboxSession.getLoggedInUser.toScala + .map(_.asString()) + .getOrElse(""))) + .log("JMAP mail spooled."), context) + context + }) case _ => SMono(queue.enqueueReactive(mail, delay)) - .doOnSuccess(_ => AuditTrail.entry - .username(() => mailboxSession.getUser.asString()) - .protocol("JMAP") - .action("EmailSubmission") - .parameters(() => ImmutableMap.of("mailId", mail.getName, - "mimeMessageId", Option(mail.getMessage) - .flatMap(message => Option(message.getMessageID)) - .getOrElse(""), - "size", mail.getMessageSize.toString, - "sender", mail.getMaybeSender.asString, - "recipients", StringUtils.join(mail.getRecipients), - "holdFor", delay.toString, - "loggedInUser", mailboxSession.getLoggedInUser.toScala - .map(_.asString()) - .getOrElse(""))) - .log("JMAP mail spooled.")) + .subscriberContext(context => { + ReactorUtils.logWithContext(() => AuditTrail.entry + .username(() => mailboxSession.getUser.asString()) + .protocol("JMAP") + .action("EmailSubmission") + .parameters(() => ImmutableMap.of("mailId", mail.getName, + "mimeMessageId", Option(mail.getMessage) + .flatMap(message => Option(message.getMessageID)) + .getOrElse(""), + "size", mail.getMessageSize.toString, + "sender", mail.getMaybeSender.asString, + "recipients", StringUtils.join(mail.getRecipients), + "holdFor", delay.toString, + "loggedInUser", mailboxSession.getLoggedInUser.toScala + .map(_.asString()) + .getOrElse(""))) + .log("JMAP mail spooled."), context) + context + }) }).`then`(SMono.fromCallable(() => LifecycleUtil.dispose(mail)).subscribeOn(Schedulers.boundedElastic())) private def retrieveDelay(mailParameters: Option[Map[ParameterName, Option[ParameterValue]]]): Try[Duration] = diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala index 7824aff7d2..3a4c8b0697 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetUpdatePerformer.scala @@ -251,16 +251,19 @@ class MailboxSetUpdatePerformer @Inject()(serializer: MailboxSerializer, val partialUpdatesOperation: SMono[Unit] = SFlux.fromIterable(validatedPatch.rightsPartialUpdates) .flatMap(partialUpdate => SMono.fromCallable(() => mailboxManager.applyRightsCommand(mailboxId, partialUpdate.asACLCommand(), mailboxSession)) - .doOnSuccess(_ => AuditTrail.entry - .username(() => mailboxSession.getUser.asString()) - .protocol("JMAP") - .action("Mailbox/set update") - .parameters(() => ImmutableMap.of("loggedInUser", mailboxSession.getLoggedInUser.toScala.map(_.asString()).getOrElse(""), - "delegator", mailboxSession.getUser.asString(), - "delegatee", partialUpdate.entryKey.getName, - "mailboxId", mailboxId.serialize(), - "rights", partialUpdate.rights.asJava.serialize())) - .log("JMAP mailbox shared.")), + .subscriberContext(context => { + ReactorUtils.logWithContext(() => AuditTrail.entry + .username(() => mailboxSession.getUser.asString()) + .protocol("JMAP") + .action("Mailbox/set update") + .parameters(() => ImmutableMap.of("loggedInUser", mailboxSession.getLoggedInUser.toScala.map(_.asString()).getOrElse(""), + "delegator", mailboxSession.getUser.asString(), + "delegatee", partialUpdate.entryKey.getName, + "mailboxId", mailboxId.serialize(), + "rights", partialUpdate.rights.asJava.serialize())) + .log("JMAP mailbox shared."), context) + context + }), maxConcurrency = 5) .`then`() diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala index 5873ab3fb0..377c1e0cdc 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala @@ -37,6 +37,7 @@ import org.apache.james.jmap.http.{Authenticator, UserProvisioning} import org.apache.james.jmap.json.ResponseSerializer import org.apache.james.jmap.{Endpoint, JMAPRoute, JMAPRoutes} import org.apache.james.mailbox.MailboxSession +import org.apache.james.util.{MDCBuilder, ReactorUtils} import org.slf4j.{Logger, LoggerFactory} import play.api.libs.json.{JsError, JsSuccess, Json} import reactor.core.publisher.{Mono, SynchronousSink} @@ -75,6 +76,9 @@ class JMAPApiRoutes @Inject() (@Named(InjectionKeys.RFC_8621) val authenticator: .onErrorResume(throwable => handleError(throwable, httpServerResponse)) .asJava() .`then`() + .contextWrite(ReactorUtils.context("MDCBuilder.IP", MDCBuilder.create() + .addToContext(MDCBuilder.IP, Option(httpServerRequest.hostAddress()).map(_.toString()).getOrElse("")) + .addToContext("x-forwarded-for", Option(httpServerRequest.requestHeaders().get("X-Forwarded-For")).getOrElse("")))) private def requestAsJsonStream(httpServerRequest: HttpServerRequest): SMono[RequestObject] = SMono.fromPublisher(httpServerRequest --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org