From 358e5aa5a98449d4dd776d754b2d2c2e23128f61 Mon Sep 17 00:00:00 2001 From: Parth Brahmbhatt Date: Tue, 17 Nov 2015 10:58:47 -0800 Subject: [PATCH] KAFKA-2852: Updating the Authorizer CLI to use a consistent way to specify a list of values for a config options. --- .../main/scala/kafka/admin/AclCommand.scala | 26 +++++++------------ .../unit/kafka/admin/AclCommandTest.scala | 16 ++++++------ docs/security.html | 20 +++++++------- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/core/src/main/scala/kafka/admin/AclCommand.scala b/core/src/main/scala/kafka/admin/AclCommand.scala index 3a6986f5d804c..f4bb2bc5e006c 100644 --- a/core/src/main/scala/kafka/admin/AclCommand.scala +++ b/core/src/main/scala/kafka/admin/AclCommand.scala @@ -27,7 +27,6 @@ import scala.collection.JavaConverters._ object AclCommand { - val Delimiter = ',' val Newline = scala.util.Properties.lineSeparator val ResourceTypeToValidOperations = Map[ResourceType, Set[Operation]] ( Topic -> Set(Read, Write, Describe, All), @@ -244,7 +243,7 @@ object AclCommand { for ((resource, acls) <- resourceToAcls) { val validOps = ResourceTypeToValidOperations(resource.resourceType) if ((acls.map(_.operation) -- validOps).nonEmpty) - CommandLineUtils.printUsageAndDie(opts.parser, s"ResourceType ${resource.resourceType} only supports operations ${validOps.mkString(Delimiter.toString)}") + CommandLineUtils.printUsageAndDie(opts.parser, s"ResourceType ${resource.resourceType} only supports operations ${validOps.mkString(",")}") } } @@ -264,31 +263,28 @@ object AclCommand { .ofType(classOf[String]) .withValuesSeparatedBy(Delimiter) - val topicOpt = parser.accepts("topic", "Comma separated list of topic to which acls should be added or removed. " + + val topicOpt = parser.accepts("topic", "topic to which acls should be added or removed. " + "A value of * indicates acl should apply to all topics.") .withRequiredArg .describedAs("topic") .ofType(classOf[String]) - .withValuesSeparatedBy(Delimiter) val clusterOpt = parser.accepts("cluster", "Add/Remove cluster acls.") - val groupOpt = parser.accepts("group", "Comma separated list of groups to which the acls should be added or removed. " + + val groupOpt = parser.accepts("group", "Consumer Group to which the acls should be added or removed. " + "A value of * indicates the acls should apply to all groups.") .withRequiredArg .describedAs("group") .ofType(classOf[String]) - .withValuesSeparatedBy(Delimiter) val addOpt = parser.accepts("add", "Indicates you are trying to add acls.") val removeOpt = parser.accepts("remove", "Indicates you are trying to remove acls.") val listOpt = parser.accepts("list", "List acls for the specified resource, use --topic or --group or --cluster to specify a resource.") - val operationsOpt = parser.accepts("operations", "Comma separated list of operations, default is All. Valid operation names are: " + Newline + + val operationsOpt = parser.accepts("operation", "Operation that is being allowed or denied. Valid operation names are: " + Newline + Operation.values.map("\t" + _).mkString(Newline) + Newline) .withRequiredArg .ofType(classOf[String]) .defaultsTo(All.name) - .withValuesSeparatedBy(Delimiter) val allowPrincipalsOpt = parser.accepts("allow-principal", "principal is in principalType:name format." + " User:* is the wild card indicating all users.") @@ -306,19 +302,17 @@ object AclCommand { .describedAs("deny-principal") .ofType(classOf[String]) - val allowHostsOpt = parser.accepts("allow-hosts", "Comma separated list of hosts from which principals listed in --allow-principals will have access. " + - "If you have specified --allow-principals then the default for this option will be set to * which allows access from all hosts.") + val allowHostsOpt = parser.accepts("allow-host", "Host from which principals listed in --allow-principal will have access. " + + "If you have specified --allow-principal then the default for this option will be set to * which allows access from all hosts.") .withRequiredArg - .describedAs("allow-hosts") + .describedAs("allow-host") .ofType(classOf[String]) - .withValuesSeparatedBy(Delimiter) - val denyHostssOpt = parser.accepts("deny-hosts", "Comma separated list of hosts from which principals listed in --deny-principals will be denied access. " + - "If you have specified --deny-principals then the default for this option will be set to * which denies access from all hosts.") + val denyHostssOpt = parser.accepts("deny-host", "Host from which principals listed in --deny-principal will be denied access. " + + "If you have specified --deny-principal then the default for this option will be set to * which denies access from all hosts.") .withRequiredArg - .describedAs("deny-hosts") + .describedAs("deny-host") .ofType(classOf[String]) - .withValuesSeparatedBy(Delimiter) val producerOpt = parser.accepts("producer", "Convenience option to add/remove acls for producer role. " + "This will generate acls that allows WRITE,DESCRIBE on topic and CREATE on cluster. ") diff --git a/core/src/test/scala/unit/kafka/admin/AclCommandTest.scala b/core/src/test/scala/unit/kafka/admin/AclCommandTest.scala index 1e9cdae50caad..0bb950dd473af 100644 --- a/core/src/test/scala/unit/kafka/admin/AclCommandTest.scala +++ b/core/src/test/scala/unit/kafka/admin/AclCommandTest.scala @@ -31,21 +31,22 @@ class AclCommandTest extends ZooKeeperTestHarness with Logging { private val Users = Set(KafkaPrincipal.fromString("User:CN=writeuser,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown"), KafkaPrincipal.fromString("User:test2")) private val Hosts = Set("host1", "host2") - private val HostsString = Hosts.mkString(AclCommand.Delimiter.toString) + private val AllowHostCommand = Array("--allow-host", "host1", "--allow-host", "host2") + private val DenyHostCommand = Array("--deny-host", "host1", "--deny-host", "host2") private val TopicResources = Set(new Resource(Topic, "test-1"), new Resource(Topic, "test-2")) private val GroupResources = Set(new Resource(Group, "testGroup-1"), new Resource(Group, "testGroup-2")) private val ResourceToCommand = Map[Set[Resource], Array[String]]( - TopicResources -> Array("--topic", "test-1,test-2"), + TopicResources -> Array("--topic", "test-1", "--topic", "test-2"), Set(Resource.ClusterResource) -> Array("--cluster"), - GroupResources -> Array("--group", "testGroup-1,testGroup-2") + GroupResources -> Array("--group", "testGroup-1", "--group", "testGroup-2") ) private val ResourceToOperations = Map[Set[Resource], (Set[Operation], Array[String])]( - TopicResources -> (Set(Read, Write, Describe), Array("--operations", "Read,Write,Describe")), - Set(Resource.ClusterResource) -> (Set(Create, ClusterAction), Array("--operations", "Create,ClusterAction")), - GroupResources -> (Set(Read).toSet[Operation], Array("--operations", "Read")) + TopicResources -> (Set(Read, Write, Describe), Array("--operation", "Read" , "--operation", "Write", "--operation", "Describe")), + Set(Resource.ClusterResource) -> (Set(Create, ClusterAction), Array("--operation", "Create", "--operation", "ClusterAction")), + GroupResources -> (Set(Read).toSet[Operation], Array("--operation", "Read")) ) private val ProducerResourceToAcls = Map[Set[Resource], Set[Acl]]( @@ -118,9 +119,8 @@ class AclCommandTest extends ZooKeeperTestHarness with Logging { private def getCmd(permissionType: PermissionType): Array[String] = { val principalCmd = if (permissionType == Allow) "--allow-principal" else "--deny-principal" - val hostCmd = if (permissionType == Allow) "--allow-hosts" else "--deny-hosts" + val cmd = if (permissionType == Allow) AllowHostCommand else DenyHostCommand - val cmd = Array(hostCmd, HostsString) Users.foldLeft(cmd) ((cmd, user) => cmd ++ Array(principalCmd, user.toString)) } diff --git a/docs/security.html b/docs/security.html index 25f15a0050a77..fa3605935440d 100644 --- a/docs/security.html +++ b/docs/security.html @@ -336,20 +336,20 @@

Command Line Interface

Principal - --allow-hosts - Comma separated list of hosts from which principals listed in --allow-principals will have access. + --allow-host + Host from which principals listed in --allow-principals will have access. if --allow-principals is specified defaults to * which translates to "all hosts" Host - --deny-hosts - Comma separated list of hosts from which principals listed in --deny-principals will be denied access. + --deny-host + Host from which principals listed in --deny-principals will be denied access. if --deny-principals is specified defaults to * which translates to "all hosts" Host - --operations - Comma separated list of operations.
+ --operation + Operation that will be allowed or denied.
Valid values are : Read, Write, Create, Delete, Alter, Describe, ClusterAction, All All Operation @@ -373,14 +373,14 @@

Examples

  • Adding Acls
    Suppose you want to add an acl "Principals User:Bob and User:Alice are allowed to perform Operation Read and Write on Topic Test-Topic from Host1 and Host2". You can do that by executing the CLI with following options: -
    bin/kafka-acls.sh --authorizer kafka.security.auth.SimpleAclAuthorizer --authorizer-properties zookeeper.connect=localhost:2181 --add --allow-principal User:Bob --allow-principal User:Alice --allow-hosts Host1,Host2 --operations Read,Write --topic Test-topic
    - By default all principals that don't have an explicit acl that allows access for an operation to a resource are denied. In rare cases where an allow acl is defined that allows access to all but some principal we will have to use the --deny-principals and --deny-host option. For example, if we want to allow all users to Read from Test-topic but only deny User:BadBob from host bad-host we can do so using following commands: -
    bin/kafka-acls.sh --authorizer kafka.security.auth.SimpleAclAuthorizer --authorizer-properties zookeeper.connect=localhost:2181 --add --allow-principal User:* --allow-hosts * --deny-principal User:BadBob --deny-hosts bad-host --operations Read--topic Test-topic
    +
    bin/kafka-acls.sh --authorizer kafka.security.auth.SimpleAclAuthorizer --authorizer-properties zookeeper.connect=localhost:2181 --add --allow-principal User:Bob --allow-principal User:Alice --allow-host Host1 --allow-host Host2 --operation Read --operation Write --topic Test-topic
    + By default all principals that don't have an explicit acl that allows access for an operation to a resource are denied. In rare cases where an allow acl is defined that allows access to all but some principal we will have to use the --deny-principal and --deny-host option. For example, if we want to allow all users to Read from Test-topic but only deny User:BadBob from host bad-host we can do so using following commands: +
    bin/kafka-acls.sh --authorizer kafka.security.auth.SimpleAclAuthorizer --authorizer-properties zookeeper.connect=localhost:2181 --add --allow-principal User:* --allow-hosts * --deny-principal User:BadBob --deny-host bad-host --operation Read--topic Test-topic
    Above examples add acls to a topic by specifying --topic [topic-name] as the resource option. Similarly user can add acls to cluster by specifying --cluster and to a consumer group by specifying --consumer-group [group-name].
  • Removing Acls
    Removing acls is pretty much the same. The only difference is instead of --add option users will have to specify --remove option. To remove the acls added by the first example above we can execute the CLI with following options: -
     bin/kafka-acls.sh --authorizer kafka.security.auth.SimpleAclAuthorizer --authorizer-properties zookeeper.connect=localhost:2181 --remove --allow-principal User:Bob --allow-principal User:Alice --allow-hosts Host1,Host2 --operations Read,Write --topic Test-topic 
  • +
     bin/kafka-acls.sh --authorizer kafka.security.auth.SimpleAclAuthorizer --authorizer-properties zookeeper.connect=localhost:2181 --remove --allow-principal User:Bob --allow-principal User:Alice --allow-host Host1 --allow-host Host2 --operation Read --operation Write --topic Test-topic 
  • List Acls
    We can list acls for any resource by specifying the --list option with the resource. To list all acls for Test-topic we can execute the CLI with following options: