Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[User management] Add feature flag to enable user management [DPP-827] #12420

Merged
merged 7 commits into from
Jan 21, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ case class ApiServerConfig(
maxTransactionsInMemoryFanOutBufferSize: Long,
enableInMemoryFanOutForLedgerApi: Boolean,
enableSelfServiceErrorCodes: Boolean,
enableUserManagement: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ private[daml] object ApiServices {
enableSelfServiceErrorCodes: Boolean,
checkOverloaded: TelemetryContext => Option[state.SubmissionResult],
commandDeduplicationFeatures: CommandDeduplicationFeatures,
enableUserManagement: Boolean,
)(implicit
materializer: Materializer,
esf: ExecutionSequencerFactory,
Expand Down Expand Up @@ -165,6 +166,7 @@ private[daml] object ApiServices {
enableSelfServiceErrorCodes,
commandDeduplicationFeatures,
optTimeServiceBackend.isDefined,
enableUserManagement = enableUserManagement,
)

val apiPackageService =
Expand Down Expand Up @@ -209,8 +211,14 @@ private[daml] object ApiServices {

val apiHealthService = new GrpcHealthService(healthChecks, errorsVersionsSwitcher)

val apiUserManagementService =
new ApiUserManagementService(userManagementStore, errorsVersionsSwitcher)
val maybeApiUserManagementService: Option[UserManagementServiceAuthorization] =
if (enableUserManagement) {
val apiUserManagementService =
new ApiUserManagementService(userManagementStore, errorsVersionsSwitcher)
val authorized =
new UserManagementServiceAuthorization(apiUserManagementService, authorizer)
Some(authorized)
} else None
pbatko-da marked this conversation as resolved.
Show resolved Hide resolved

apiTimeServiceOpt.toList :::
writeServiceBackedApiServices :::
Expand All @@ -224,8 +232,7 @@ private[daml] object ApiServices {
apiReflectionService,
apiHealthService,
apiVersionService,
new UserManagementServiceAuthorization(apiUserManagementService, authorizer),
)
) ::: maybeApiUserManagementService.toList
}

private def intitializeWriteServiceBackedApiServices(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ object StandaloneApiServer {
checkOverloaded = checkOverloaded,
userManagementStore = userManagementStore,
commandDeduplicationFeatures = commandDeduplicationFeatures,
enableUserManagement = config.enableUserManagement,
)(materializer, executionSequencerFactory, loggingContext)
.map(_.withServices(otherServices))
apiServer <- new LedgerApiServer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ private[apiserver] final class ApiVersionService private (
enableSelfServiceErrorCodes: Boolean,
commandDeduplicationFeatures: CommandDeduplicationFeatures,
enableStaticTime: Boolean,
enableUserManagement: Boolean,
)(implicit
loggingContext: LoggingContext,
ec: ExecutionContext,
Expand All @@ -54,7 +55,7 @@ private[apiserver] final class ApiVersionService private (

private val featuresDescriptor =
FeaturesDescriptor.of(
userManagement = Some(UserManagementFeature(supported = true)),
userManagement = Some(UserManagementFeature(supported = enableUserManagement)),
experimental = Some(
ExperimentalFeatures(
selfServiceErrorCodes =
Expand Down Expand Up @@ -106,10 +107,12 @@ private[apiserver] object ApiVersionService {
enableSelfServiceErrorCodes: Boolean,
commandDeduplicationFeatures: CommandDeduplicationFeatures,
enableStaticTime: Boolean,
enableUserManagement: Boolean,
)(implicit loggingContext: LoggingContext, ec: ExecutionContext): ApiVersionService =
new ApiVersionService(
enableSelfServiceErrorCodes,
commandDeduplicationFeatures,
enableStaticTime,
enableUserManagement = enableUserManagement,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ import scala.concurrent.{ExecutionContext, Future}

object UserManagementConfig {

val default: UserManagementConfig = UserManagementConfig(
maximumCacheSize = 100,
cacheExpiryAfterWriteInSeconds = 5,
val DefaultMaximumCacheSize = 100
val DefaultCacheExpiryAfterWriteInSeconds = 5

def default(enabled: Boolean): UserManagementConfig = UserManagementConfig(
enabled = enabled,
maximumCacheSize = DefaultMaximumCacheSize,
cacheExpiryAfterWriteInSeconds = DefaultCacheExpiryAfterWriteInSeconds,
)
}
final case class UserManagementConfig(
enabled: Boolean,
maximumCacheSize: Int,
cacheExpiryAfterWriteInSeconds: Int,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ object Config {
maxDeduplicationDuration = None,
extra = extra,
enableSelfServiceErrorCodes = true,
userManagementConfig = UserManagementConfig.default,
userManagementConfig = UserManagementConfig.default(enabled = false),
)

def ownerWithoutExtras(name: String, args: collection.Seq[String]): ResourceOwner[Config[Unit]] =
Expand Down Expand Up @@ -652,10 +652,19 @@ object Config {
)
.action((_, config: Config[Extra]) => config.copy(enableSelfServiceErrorCodes = false))

opt[Boolean]("feature-user-management")
pbatko-da marked this conversation as resolved.
Show resolved Hide resolved
.optional()
.text(
"Whether to enable participant user management."
)
.action((enabled, config: Config[Extra]) =>
config.withUserManagementConfig(_.copy(enabled = enabled))
)

opt[Int]("user-management-cache-expiry")
.optional()
.text(
s"Defaults to ${UserManagementConfig.default.cacheExpiryAfterWriteInSeconds} seconds. " +
s"Defaults to ${UserManagementConfig.DefaultCacheExpiryAfterWriteInSeconds} seconds. " +
// TODO participant user management: Update max delay to 2x the configured value when made use of in throttled stream authorization.
"Determines the maximum delay for propagating user management state changes."
)
Expand All @@ -666,7 +675,7 @@ object Config {
opt[Int]("user-management-max-cache-size")
.optional()
.text(
s"Defaults to ${UserManagementConfig.default.maximumCacheSize} entries. " +
s"Defaults to ${UserManagementConfig.DefaultMaximumCacheSize} entries. " +
"Determines the maximum in-memory cache size for user management state."
)
.action((value, config: Config[Extra]) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ trait ConfigProvider[ExtraConfig] {
participantConfig.maxTransactionsInMemoryFanOutBufferSize,
enableInMemoryFanOutForLedgerApi = config.enableInMemoryFanOutForLedgerApi,
enableSelfServiceErrorCodes = config.enableSelfServiceErrorCodes,
enableUserManagement = config.userManagementConfig.enabled,
)

def partyConfig(@unused config: Config[ExtraConfig]): PartyConfiguration =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,41 @@ final class ConfigSpec
}
}

it should "handle '--feature-user-management' flag correctly" in {
configParser(
Seq(
dumpIndexMetadataCommand,
"some-jdbc-url",
"--feature-user-management",
)
) shouldBe None

configParser(
Seq(
dumpIndexMetadataCommand,
"some-jdbc-url",
"--feature-user-management",
"false",
)
).value.userManagementConfig.enabled shouldBe false

configParser(
Seq(
dumpIndexMetadataCommand,
"some-jdbc-url",
"--feature-user-management",
"true",
)
).value.userManagementConfig.enabled shouldBe true

configParser(
Seq(
dumpIndexMetadataCommand,
"some-jdbc-url",
)
).value.userManagementConfig.enabled shouldBe false
}

it should "set REQUIRE client-auth when the parameter is not explicitly provided" in {
val aValidTlsOptions = List(s"$certRevocationChecking", "false")
val config =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ final class SandboxServer(
CommandDeduplicationType.SYNC_ONLY,
maxDeduplicationDurationEnforced = false,
),
enableUserManagement = config.userManagementConfig.enabled,
)(materializer, executionSequencerFactory, loggingContext)
apiServer <- new LedgerApiServer(
apiServicesOwner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,19 @@ class CommonCliBase(name: LedgerName) {
)
.action((_, config: SandboxConfig) => config.copy(enableSelfServiceErrorCodes = false))

opt[Boolean]("feature-user-management")
.optional()
.text(
"Whether to enable participant user management."
)
.action((enabled, config: SandboxConfig) =>
config.withUserManagementConfig(_.copy(enabled = enabled))
)

opt[Int]("user-management-cache-expiry")
.optional()
.text(
s"Defaults to ${UserManagementConfig.default.cacheExpiryAfterWriteInSeconds} seconds. " +
s"Defaults to ${UserManagementConfig.DefaultCacheExpiryAfterWriteInSeconds} seconds. " +
// TODO participant user management: Update max delay to 2x the configured value when made use of in throttled stream authorization.
"Determines the maximum delay for propagating user management state changes."
)
Expand All @@ -407,7 +416,7 @@ class CommonCliBase(name: LedgerName) {
opt[Int]("user-management-max-cache-size")
.optional()
.text(
s"Defaults to ${UserManagementConfig.default.maximumCacheSize} entries. " +
s"Defaults to ${UserManagementConfig.DefaultMaximumCacheSize} entries. " +
"Determines the maximum in-memory cache size for user management state."
)
.action((value, config: SandboxConfig) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ object SandboxConfig {
sqlStartMode = Some(DefaultSqlStartupMode),
enableCompression = false,
enableSelfServiceErrorCodes = true,
userManagementConfig = UserManagementConfig.default,
userManagementConfig = UserManagementConfig.default(true),
pbatko-da marked this conversation as resolved.
Show resolved Hide resolved
)

sealed abstract class EngineMode extends Product with Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,24 @@ abstract class CommonCliSpecBase(
)
}

"handle '--feature-user-management' flag correctly" in {
checkOptionFail(
Array("--feature-user-management")
)
checkOption(
Array("--feature-user-management", "false"),
_.withUserManagementConfig(_.copy(enabled = false)),
)
checkOption(
Array("--feature-user-management", "true"),
_.withUserManagementConfig(_.copy(enabled = true)),
)
checkOption(
Array(),
_.withUserManagementConfig(_.copy(enabled = true)),
)
}

"handle '--user-management-max-cache-size' flag correctly" in {
// missing cache size value
checkOptionFail(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ class Runner(config: SandboxConfig) extends ResourceOwner[Port] {
maxTransactionsInMemoryFanOutBufferSize = 0L,
enableInMemoryFanOutForLedgerApi = false,
enableSelfServiceErrorCodes = config.enableSelfServiceErrorCodes,
enableUserManagement = config.userManagementConfig.enabled,
)
dbSupport <- DbSupport.owner(
jdbcUrl = apiServerConfig.jdbcUrl,
Expand Down