From 8d34be5129f0dff1f19fb4264aced6d4d307fe7e Mon Sep 17 00:00:00 2001
From: HJ Kim <hj.kim@r3.com>
Date: Thu, 23 Jun 2022 21:52:42 +0100
Subject: [PATCH] ENT-6714: Fix Corda logging database password

This commit ports the previously implemented fix from Corda ENT. Due to
the unrelated changes and merge conflict, the fix has been manually
copied rather than cherry-picked.
---
 .../config/schema/v1/ConfigSections.kt        | 26 ++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt
index 323a14fde0..79a9c81dea 100644
--- a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt
+++ b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt
@@ -47,6 +47,7 @@ import net.corda.nodeapi.internal.persistence.DatabaseConfig
 import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
 import net.corda.notary.experimental.bftsmart.BFTSmartConfig
 import net.corda.notary.experimental.raft.RaftConfig
+import java.util.Properties
 
 internal object UserSpec : Configuration.Specification<User>("User") {
     private val username by string().optional()
@@ -67,9 +68,32 @@ internal object UserSpec : Configuration.Specification<User>("User") {
 internal object SecurityConfigurationSpec : Configuration.Specification<SecurityConfiguration>("SecurityConfiguration") {
     private object AuthServiceSpec : Configuration.Specification<SecurityConfiguration.AuthService>("AuthService") {
         private object DataSourceSpec : Configuration.Specification<SecurityConfiguration.AuthService.DataSource>("DataSource") {
+            fun Properties.enablePasswordMasking(): Properties {
+                class PwMasking : Properties() {
+                    fun maskPassword(): Properties {
+                        if (!containsKey("password")) return this
+                        val propsNoPassword = Properties()
+                        // if the properties are passed in to the constructor as defaults
+                        // they don't get printed so adding all keys explicitly
+                        propsNoPassword.putAll(this)
+                        propsNoPassword.setProperty("password", "***")
+                        return propsNoPassword
+                    }
+
+                    override fun toString(): String {
+                        val props = maskPassword()
+                        return props.toString()
+                    }
+                }
+
+                val masker = PwMasking()
+                masker.putAll(this)
+                return masker
+            }
+
             private val type by enum(AuthDataSourceType::class)
             private val passwordEncryption by enum(PasswordEncryption::class).optional().withDefaultValue(SecurityConfiguration.AuthService.DataSource.Defaults.passwordEncryption)
-            private val connection by nestedObject(sensitive = true).map(::toProperties).optional()
+            private val connection by nestedObject(sensitive = true).map{ toProperties(it).enablePasswordMasking() }.optional()
             private val users by nested(UserSpec).list().optional()
 
             override fun parseValid(configuration: Config, options: Configuration.Options): Valid<SecurityConfiguration.AuthService.DataSource> {