diff --git a/actor-tests/src/test/scala/org/apache/pekko/actor/ActorSystemSpec.scala b/actor-tests/src/test/scala/org/apache/pekko/actor/ActorSystemSpec.scala index a5c25b9ee98..c8af272fa9a 100644 --- a/actor-tests/src/test/scala/org/apache/pekko/actor/ActorSystemSpec.scala +++ b/actor-tests/src/test/scala/org/apache/pekko/actor/ActorSystemSpec.scala @@ -392,6 +392,23 @@ class ActorSystemSpec extends PekkoSpec(ActorSystemSpec.config) with ImplicitSen } } finally shutdown(sys) } + "not include username in toString" in { + // Actor System toString is output to logs and we don't want env variable values appearing in logs + val system = + ActorSystem( + "config-test-system", + ConfigFactory + .parseString("""pekko.test.java.property.home = "${user.home}"""") + .withFallback(PekkoSpec.testConf)) + try { + val debugText = system.settings.toString + val username = System.getProperty("user.name") + val userHome = System.getProperty("user.home") + (debugText should not).include(username) + (debugText should not).include(userHome) + debugText should include("") + } finally shutdown(system) + } } } diff --git a/actor-typed-tests/src/test/scala/org/apache/pekko/actor/typed/ActorSystemSpec.scala b/actor-typed-tests/src/test/scala/org/apache/pekko/actor/typed/ActorSystemSpec.scala new file mode 100644 index 00000000000..cfd411d59ba --- /dev/null +++ b/actor-typed-tests/src/test/scala/org/apache/pekko/actor/typed/ActorSystemSpec.scala @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.pekko.actor.typed + +import com.typesafe.config.ConfigFactory +import org.apache.pekko +import pekko.actor.typed.scaladsl.Behaviors +import pekko.testkit.PekkoSpec + +import scala.annotation.nowarn + +@nowarn("msg=possible missing interpolator") +class ActorSystemSpec extends PekkoSpec { + "ActorSystem" should { + "not include username in toString" in { + // Actor System toString is output to logs and we don't want env variable values appearing in logs + val system = ActorSystem(Behaviors.empty[String], "config-test-system", + ConfigFactory + .parseString("""pekko.test.java.property.home = "${user.home}"""") + .withFallback(PekkoSpec.testConf)) + try { + val debugText = system.settings.toString + val username = System.getProperty("user.name") + val userHome = System.getProperty("user.home") + (debugText should not).include(username) + (debugText should not).include(userHome) + debugText should include("") + } finally { + system.terminate() + } + } + } +} diff --git a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/ActorSystem.scala b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/ActorSystem.scala index 4cac4e496e8..d60d91077ee 100644 --- a/actor-typed/src/main/scala/org/apache/pekko/actor/typed/ActorSystem.scala +++ b/actor-typed/src/main/scala/org/apache/pekko/actor/typed/ActorSystem.scala @@ -19,7 +19,6 @@ import scala.concurrent.{ ExecutionContextExecutor, Future } import com.typesafe.config.{ Config, ConfigFactory } import org.slf4j.Logger - import org.apache.pekko import pekko.{ actor => classic, Done } import pekko.actor.{ Address, BootstrapSetup, ClassicActorSystemProvider } @@ -29,7 +28,7 @@ import pekko.actor.typed.internal.{ EventStreamExtension, InternalRecipientRef } import pekko.actor.typed.internal.adapter.{ ActorSystemAdapter, GuardianStartupBehavior, PropsAdapter } import pekko.actor.typed.receptionist.Receptionist import pekko.annotation.DoNotInherit -import pekko.util.Helpers.Requiring +import pekko.util.Helpers.{ ConfigOps, Requiring } /** * An ActorSystem is home to a hierarchy of Actors. It is created using @@ -324,7 +323,7 @@ final class Settings(val config: Config, val classicSettings: classic.ActorSyste /** * Returns the String representation of the Config that this Settings is backed by */ - override def toString: String = config.root.render + override def toString: String = config.renderWithRedactions() private val typedConfig = config.getConfig("pekko.actor.typed") diff --git a/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala b/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala index f5a113e0780..b91961d07d5 100644 --- a/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala +++ b/actor/src/main/scala/org/apache/pekko/actor/ActorSystem.scala @@ -489,7 +489,7 @@ object ActorSystem { /** * Returns the String representation of the Config that this Settings is backed by */ - override def toString: String = config.root.render + override def toString: String = config.renderWithRedactions() } diff --git a/actor/src/main/scala/org/apache/pekko/dispatch/Dispatchers.scala b/actor/src/main/scala/org/apache/pekko/dispatch/Dispatchers.scala index 791cba0ff09..06d7c2f5106 100644 --- a/actor/src/main/scala/org/apache/pekko/dispatch/Dispatchers.scala +++ b/actor/src/main/scala/org/apache/pekko/dispatch/Dispatchers.scala @@ -14,8 +14,9 @@ package org.apache.pekko.dispatch import java.util.concurrent.{ ConcurrentHashMap, ThreadFactory } -import scala.concurrent.ExecutionContext import scala.annotation.{ nowarn, tailrec } +import scala.concurrent.ExecutionContext + import com.typesafe.config.{ Config, ConfigFactory, ConfigValueType } import org.apache.pekko import pekko.ConfigurationException @@ -259,7 +260,8 @@ class Dispatchers @InternalApi private[pekko] ( */ private def configuratorFrom(cfg: Config): MessageDispatcherConfigurator = { if (!cfg.hasPath("id")) - throw new ConfigurationException("Missing dispatcher 'id' property in config: " + cfg.root.render) + throw new ConfigurationException("Missing dispatcher 'id' property in config: " + + cfg.renderWithRedactions()) cfg.getString("type") match { case "Dispatcher" => new DispatcherConfigurator(cfg, prerequisites) diff --git a/actor/src/main/scala/org/apache/pekko/util/Helpers.scala b/actor/src/main/scala/org/apache/pekko/util/Helpers.scala index 2d9b0ef1785..6b00bd58ed9 100644 --- a/actor/src/main/scala/org/apache/pekko/util/Helpers.scala +++ b/actor/src/main/scala/org/apache/pekko/util/Helpers.scala @@ -28,16 +28,12 @@ package org.apache.pekko.util import java.time.{ Instant, LocalDateTime, ZoneId } import java.time.format.DateTimeFormatter -import java.util.Comparator -import java.util.Locale +import java.util.{ Comparator, Locale } import java.util.concurrent.TimeUnit import java.util.regex.Pattern - import scala.annotation.tailrec -import scala.concurrent.duration.Duration -import scala.concurrent.duration.FiniteDuration - -import com.typesafe.config.Config +import scala.concurrent.duration.{ Duration, FiniteDuration } +import com.typesafe.config.{ Config, ConfigRenderOptions } object Helpers { @@ -179,6 +175,22 @@ object Helpers { def getNanosDuration(path: String): FiniteDuration = getDuration(path, TimeUnit.NANOSECONDS) + /** + * Used to redact sensitive information in config data when we are logging it + * or adding it to exception messages. + * + * This includes redacting environment variable values and the username associated with the running process. + * + * @return redacted version of the configuration text + * @see https://github.com/apache/incubator-pekko/pull/771 + * @since 1.0.2 + */ + def renderWithRedactions(): String = { + val username = System.getProperty("user.name") + val configText = config.root.render(ConfigRenderOptions.defaults().setShowEnvVariableValues(false)) + configText.replace(username, "") + } + private def getDuration(path: String, unit: TimeUnit): FiniteDuration = Duration(config.getDuration(path, unit), unit) }