{"action":"created","comment":{"url":"https://api.github.com/repos/apache/kafka/pulls/comments/42184006","id":42184006,"diff_hunk":"@@ -0,0 +1,360 @@\n+/**\n+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE\n+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file\n+ * to You under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the\n+ * License. You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on\n+ * an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the\n+ * specific language governing permissions and limitations under the License.\n+ */\n+package integration.kafka.api\n+\n+import java.io.{DataInputStream, DataOutputStream}\n+import java.net.Socket\n+import java.nio.ByteBuffer\n+import java.util.concurrent.{ExecutionException}\n+import java.util.{ArrayList, Properties}\n+\n+import kafka.api._\n+import kafka.cluster.{BrokerEndPoint, Broker, EndPoint}\n+import kafka.common.{ErrorMapping, OffsetAndMetadata, OffsetMetadata, TopicAndPartition}\n+import kafka.controller.{KafkaController, LeaderIsrAndControllerEpoch}\n+import kafka.coordinator.ConsumerCoordinator\n+import kafka.integration.KafkaServerTestHarness\n+import kafka.message.ByteBufferMessageSet\n+import kafka.security.auth._\n+import kafka.server.KafkaConfig\n+import kafka.utils.TestUtils\n+import org.apache.kafka.clients.consumer.{Consumer, ConsumerRecord, KafkaConsumer}\n+import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}\n+import org.apache.kafka.common.TopicPartition\n+import org.apache.kafka.common.errors.{TimeoutException, ApiException}\n+import org.apache.kafka.common.protocol.{Errors, SecurityProtocol}\n+import org.apache.kafka.common.security.auth.KafkaPrincipal\n+import org.junit.Assert._\n+import org.junit.{After, Assert, Before, Test}\n+\n+import scala.collection.JavaConverters._\n+import scala.collection.mutable\n+import scala.collection.mutable.Buffer\n+\n+class AuthorizerIntegrationTest extends KafkaServerTestHarness {\n+  val topic = \"topic\"\n+  val part = 0\n+  val brokerId = 0\n+  val correlationId = 0\n+  val clientId = \"client-Id\"\n+  val tp = new TopicPartition(topic, part)\n+  val topicAndPartition = new TopicAndPartition(topic, part)\n+  val group = \"my-group\"\n+  val topicResource = new Resource(Topic, topic)\n+  val groupResource = new Resource(ConsumerGroup, group)\n+\n+\n+  val authorizer = new SimpleAclAuthorizer\n+\n+  val consumers = Buffer[KafkaConsumer[Array[Byte], Array[Byte]]]()\n+  val producers = Buffer[KafkaProducer[Array[Byte], Array[Byte]]]()\n+\n+  val numServers = 1\n+  val producerCount = 1\n+  val consumerCount = 2\n+  val producerConfig = new Properties\n+  val numRecords = 1\n+\n+  val overridingProps = new Properties()\n+  overridingProps.put(KafkaConfig.AuthorizerClassNameProp, classOf[SimpleAclAuthorizer].getName)\n+  overridingProps.put(KafkaConfig.BrokerIdProp, brokerId.toString)\n+  overridingProps.put(KafkaConfig.OffsetsTopicPartitionsProp, \"1\")\n+\n+  val partitionStateInfo = new PartitionStateInfo(new LeaderIsrAndControllerEpoch(LeaderAndIsr(brokerId,\n+    Int.MaxValue, List(brokerId), LeaderAndIsr.initialZKVersion), KafkaController.InitialControllerEpoch), Set(brokerId))\n+  val endPoint = new EndPoint(\"localhost\", 0, SecurityProtocol.PLAINTEXT)\n+  \n+  val RequestKeyToRequest = mutable.LinkedHashMap[Short, RequestOrResponse](\n+    RequestKeys.MetadataKey -> new TopicMetadataRequest(List(topic), correlationId),\n+    RequestKeys.ProduceKey -> ProducerRequest(ProducerRequest.CurrentVersion, correlationId, clientId, 1, 100,\n+      collection.mutable.Map(topicAndPartition -> new ByteBufferMessageSet(ByteBuffer.wrap(\"test\".getBytes)))),\n+    RequestKeys.FetchKey -> new FetchRequest(requestInfo = Map(topicAndPartition -> new PartitionFetchInfo(0, 100))),\n+    RequestKeys.OffsetsKey -> new OffsetRequest(Map(topicAndPartition -> new PartitionOffsetRequestInfo(-1, 0))),\n+    RequestKeys.OffsetCommitKey -> new OffsetCommitRequest(groupId = group, requestInfo = Map(topicAndPartition ->\n+      new OffsetAndMetadata(new OffsetMetadata(0)))),\n+    RequestKeys.OffsetFetchKey -> new OffsetFetchRequest(groupId = group, requestInfo = Seq(topicAndPartition)),\n+    RequestKeys.ConsumerMetadataKey -> new ConsumerMetadataRequest(group = group),\n+    RequestKeys.UpdateMetadataKey -> UpdateMetadataRequest(UpdateMetadataRequest.CurrentVersion, correlationId, clientId, brokerId,\n+      Int.MaxValue, Map(topicAndPartition -> partitionStateInfo), Set(new Broker(brokerId, Map(SecurityProtocol.PLAINTEXT -> endPoint)))),\n+    RequestKeys.LeaderAndIsrKey -> new LeaderAndIsrRequest(LeaderAndIsrRequest.CurrentVersion, correlationId, clientId,\n+      brokerId, Int.MaxValue, Map((topic, part) -> partitionStateInfo), Set(new BrokerEndPoint(brokerId,\"localhost\", 0))),\n+    RequestKeys.StopReplicaKey -> StopReplicaRequest(StopReplicaRequest.CurrentVersion, correlationId, clientId, brokerId,\n+      Int.MaxValue, true, Set(topicAndPartition)),\n+    RequestKeys.ControlledShutdownKey -> ControlledShutdownRequest(ControlledShutdownRequest.CurrentVersion, correlationId, Some(clientId), brokerId)\n+  )\n+\n+  val RequestKeyToResponseDeserializer: Map[Short, (ByteBuffer) => RequestOrResponse] =\n+    Map(RequestKeys.MetadataKey -> TopicMetadataResponse.readFrom,\n+      RequestKeys.ProduceKey -> ProducerResponse.readFrom,\n+      RequestKeys.FetchKey -> ((bytes: ByteBuffer) => FetchResponse.readFrom(bytes, FetchRequest.CurrentVersion)),\n+      RequestKeys.OffsetsKey -> OffsetResponse.readFrom,\n+      RequestKeys.OffsetCommitKey -> OffsetCommitResponse.readFrom,\n+      RequestKeys.OffsetFetchKey -> OffsetFetchResponse.readFrom,\n+      RequestKeys.ConsumerMetadataKey -> ConsumerMetadataResponse.readFrom,\n+      RequestKeys.UpdateMetadataKey -> UpdateMetadataResponse.readFrom,\n+      RequestKeys.LeaderAndIsrKey -> LeaderAndIsrResponse.readFrom,\n+      RequestKeys.StopReplicaKey -> StopReplicaResponse.readFrom,\n+      RequestKeys.ControlledShutdownKey -> ControlledShutdownResponse.readFrom\n+    )\n+\n+  val RequestKeyToErrorCode = Map[Short, (Nothing) => Short](\n+    RequestKeys.MetadataKey -> ((resp: TopicMetadataResponse) => resp.topicsMetadata.find(_.topic == topic).get.errorCode),\n+    RequestKeys.ProduceKey -> ((resp: ProducerResponse) => resp.status.find(_._1 == topicAndPartition).get._2.error),\n+    RequestKeys.FetchKey -> ((resp: FetchResponse) => resp.data.find(_._1 == topicAndPartition).get._2.error),\n+    RequestKeys.OffsetsKey -> ((resp: OffsetResponse) => resp.partitionErrorAndOffsets.find(_._1 == topicAndPartition).get._2.error),\n+    RequestKeys.OffsetCommitKey -> ((resp: OffsetCommitResponse) => resp.commitStatus.find(_._1 == topicAndPartition).get._2),\n+    RequestKeys.OffsetFetchKey -> ((resp: OffsetFetchResponse) => resp.requestInfo.find(_._1 == topicAndPartition).get._2.error),\n+    RequestKeys.ConsumerMetadataKey -> ((resp: ConsumerMetadataResponse) => resp.errorCode),\n+    RequestKeys.UpdateMetadataKey -> ((resp: UpdateMetadataResponse) => resp.errorCode),\n+    RequestKeys.LeaderAndIsrKey -> ((resp: LeaderAndIsrResponse) => resp.responseMap.find(_._1 == (topic, part)).get._2),\n+    RequestKeys.StopReplicaKey -> ((resp: StopReplicaResponse) => resp.responseMap.find(_._1 == topicAndPartition).get._2),\n+    RequestKeys.ControlledShutdownKey -> ((resp: ControlledShutdownResponse) => resp.errorCode)\n+  )\n+\n+  val RequestKeysToAcls = Map[Short, Map[Resource, Set[Acl]]](\n+    RequestKeys.MetadataKey -> Map(topicResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Describe))),\n+    RequestKeys.ProduceKey -> Map(topicResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Write))),\n+    RequestKeys.FetchKey -> Map(topicResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read))),\n+    RequestKeys.OffsetsKey -> Map(topicResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Describe))),\n+    RequestKeys.OffsetCommitKey -> Map(topicResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read)),\n+      groupResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read))),\n+    RequestKeys.OffsetFetchKey -> Map(topicResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read)),\n+      groupResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read))),\n+    RequestKeys.ConsumerMetadataKey -> Map(topicResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read)),\n+      groupResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read))),\n+    RequestKeys.UpdateMetadataKey -> Map(Resource.ClusterResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, ClusterAction))),\n+    RequestKeys.LeaderAndIsrKey -> Map(Resource.ClusterResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, ClusterAction))),\n+    RequestKeys.StopReplicaKey -> Map(Resource.ClusterResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, ClusterAction))),\n+    RequestKeys.ControlledShutdownKey -> Map(Resource.ClusterResource -> Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow,Acl.WildCardHost, ClusterAction)))\n+  )\n+\n+  // configure the servers and clients\n+  override def generateConfigs() = TestUtils.createBrokerConfigs(1, zkConnect, enableControlledShutdown = false).map(KafkaConfig.fromProps(_, overridingProps))\n+\n+  @Before\n+  override def setUp() {\n+    super.setUp()\n+\n+    authorizer.configure(this.servers.head.config.originals())\n+    addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, ClusterAction)), Resource.ClusterResource)\n+\n+    for (i <- 0 until producerCount)\n+      producers += TestUtils.createNewProducer(TestUtils.getBrokerListStrFromServers(servers),\n+        acks = 1)\n+    for (i <- 0 until consumerCount)\n+      consumers += TestUtils.createNewConsumer(TestUtils.getBrokerListStrFromServers(servers),\n+        groupId = group,\n+        partitionAssignmentStrategy = \"range\")\n+\n+    // create the consumer offset topic\n+    TestUtils.createTopic(zkClient, ConsumerCoordinator.OffsetsTopicName,\n+      1,\n+      1,\n+      servers,\n+      servers.head.consumerCoordinator.offsetsTopicConfigs)\n+    // create the test topic with all the brokers as replicas\n+    TestUtils.createTopic(this.zkClient, topic, 1, 1, this.servers)\n+  }\n+\n+  @After\n+  override def tearDown() = {\n+    removeAllAcls\n+    super.tearDown()\n+  }\n+\n+  @Test\n+  def testAuthorization() {\n+    val socket = new Socket(\"localhost\", servers.head.boundPort())\n+\n+    for ((key, request) <- RequestKeyToRequest) {\n+\n+      removeAllAcls\n+\n+      val buffer = ByteBuffer.allocate(request.sizeInBytes)\n+      request.writeTo(buffer)\n+      buffer.rewind()\n+      val requestBytes = buffer.array()\n+\n+      sendRequestAndVerifyResponseErrorCode(socket, key, requestBytes, ErrorMapping.AuthorizationCode)\n+\n+      for ((resource, acls) <- RequestKeysToAcls(key))\n+        addAndVerifyAcls(acls, resource)\n+\n+      sendRequestAndVerifyResponseErrorCode(socket, key, requestBytes, ErrorMapping.NoError)\n+    }\n+  }\n+\n+    @Test\n+    def testProduceNeedsAuthorization() {\n+    addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Describe)), topicResource)\n+      try {\n+        sendRecords(numRecords, tp)\n+        Assert.fail(\"should have thrown exception\")\n+      } catch {\n+        case e: ApiException => Assert.assertEquals(Errors.AUTHORIZATION_FAILED.exception().getMessage, e.getMessage)\n+      }\n+    }\n+\n+    @Test\n+    def testOnlyWritePermissionAllowsWritingToProducer() {\n+      addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Write)), topicResource)\n+      try {\n+        sendRecords(numRecords, tp)\n+      } catch {\n+        case e: Exception => Assert.fail(\"Should not fail\")\n+      }\n+    }\n+\n+    @Test\n+    def testCreatePermissionNeededForWritingToNonExistentTopic() {\n+      val newTopic = \"newTopic\"\n+      val topicPartition = new TopicPartition(newTopic, 0)\n+      addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Write)), new Resource(Topic, newTopic))\n+      try {\n+        sendRecords(numRecords, topicPartition)\n+        Assert.fail(\"should have thrown exception\")\n+      } catch {\n+        case e: TimeoutException =>\n+        //TODO Need to update the producer so it actually throws the server side of exception.\n+        case e: Exception => Assert.fail(\"Only timeout exception should be thrown.\")\n+      }\n+\n+      addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Create)), Resource.ClusterResource)\n+      try {\n+        sendRecords(numRecords, topicPartition)\n+      } catch {\n+        case e: Exception => Assert.fail(\"No exception should be thrown.\")\n+      }\n+    }\n+\n+    @Test\n+    def testConsumerNeedsAuthorization() {\n+      addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Write)), topicResource)\n+      //TODO: Ideally we would want to test that when consumerGroup permission is not present we still get an AuthorizationException\n+      //but the consumer fetcher currently waits forever for the consumer metadata to become available.\n+      addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Read)), groupResource)\n+      sendRecords(1, tp)\n+      try {\n+        this.consumers.head.assign(List(tp).asJava)\n+        consumeRecords(this.consumers.head)\n+        Assert.fail(\"should have thrown exception\")\n+      } catch {\n+        case e: ApiException => Assert.assertEquals(\"Not authorized to read from topic-0\", e.getMessage)\n+      }\n+    }\n+\n+    @Test\n+    def testAllowingReadOnTopicAndGroupAllowsReading() {\n+      addAndVerifyAcls(Set(new Acl(KafkaPrincipal.ANONYMOUS, Allow, Acl.WildCardHost, Write)), topicResource)","path":"core/src/test/scala/integration/kafka/api/AuthorizerIntegrationTest.scala","position":258,"original_position":258,"commit_id":"b39c4f0db0a27816b429017a26e8b470a3318438","original_commit_id":"ee1d00c1e1a3c2188baa8fd127c8f7117f5edb39","user":{"login":"junrao","id":132330,"avatar_url":"https://avatars.githubusercontent.com/u/132330?v=3","gravatar_id":"","url":"https://api.github.com/users/junrao","html_url":"https://github.com/junrao","followers_url":"https://api.github.com/users/junrao/followers","following_url":"https://api.github.com/users/junrao/following{/other_user}","gists_url":"https://api.github.com/users/junrao/gists{/gist_id}","starred_url":"https://api.github.com/users/junrao/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/junrao/subscriptions","organizations_url":"https://api.github.com/users/junrao/orgs","repos_url":"https://api.github.com/users/junrao/repos","events_url":"https://api.github.com/users/junrao/events{/privacy}","received_events_url":"https://api.github.com/users/junrao/received_events","type":"User","site_admin":false},"body":"Could we add at least one end to end test to make sure we can do ACL based on SSL peer principal?","created_at":"2015-10-15T21:37:31Z","updated_at":"2015-10-15T21:37:31Z","html_url":"https://github.com/apache/kafka/pull/300#discussion_r42184006","pull_request_url":"https://api.github.com/repos/apache/kafka/pulls/300","_links":{"self":{"href":"https://api.github.com/repos/apache/kafka/pulls/comments/42184006"},"html":{"href":"https://github.com/apache/kafka/pull/300#discussion_r42184006"},"pull_request":{"href":"https://api.github.com/repos/apache/kafka/pulls/300"}}},"pull_request":{"url":"https://api.github.com/repos/apache/kafka/pulls/300","id":47475240,"html_url":"https://github.com/apache/kafka/pull/300","diff_url":"https://github.com/apache/kafka/pull/300.diff","patch_url":"https://github.com/apache/kafka/pull/300.patch","issue_url":"https://api.github.com/repos/apache/kafka/issues/300","number":300,"state":"open","locked":false,"title":"KAFKA-2598: Adding integration test for the authorizer at API level. …","user":{"login":"Parth-Brahmbhatt","id":6914358,"avatar_url":"https://avatars.githubusercontent.com/u/6914358?v=3","gravatar_id":"","url":"https://api.github.com/users/Parth-Brahmbhatt","html_url":"https://github.com/Parth-Brahmbhatt","followers_url":"https://api.github.com/users/Parth-Brahmbhatt/followers","following_url":"https://api.github.com/users/Parth-Brahmbhatt/following{/other_user}","gists_url":"https://api.github.com/users/Parth-Brahmbhatt/gists{/gist_id}","starred_url":"https://api.github.com/users/Parth-Brahmbhatt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Parth-Brahmbhatt/subscriptions","organizations_url":"https://api.github.com/users/Parth-Brahmbhatt/orgs","repos_url":"https://api.github.com/users/Parth-Brahmbhatt/repos","events_url":"https://api.github.com/users/Parth-Brahmbhatt/events{/privacy}","received_events_url":"https://api.github.com/users/Parth-Brahmbhatt/received_events","type":"User","site_admin":false},"body":"…Some bug fixes that I encountered while running the tests.","created_at":"2015-10-12T23:21:58Z","updated_at":"2015-10-15T21:37:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a421f9a3b6b588f902f49250f6cfee8631077270","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/kafka/pulls/300/commits","review_comments_url":"https://api.github.com/repos/apache/kafka/pulls/300/comments","review_comment_url":"https://api.github.com/repos/apache/kafka/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/kafka/issues/300/comments","statuses_url":"https://api.github.com/repos/apache/kafka/statuses/b39c4f0db0a27816b429017a26e8b470a3318438","head":{"label":"Parth-Brahmbhatt:KAFKA-2598","ref":"KAFKA-2598","sha":"b39c4f0db0a27816b429017a26e8b470a3318438","user":{"login":"Parth-Brahmbhatt","id":6914358,"avatar_url":"https://avatars.githubusercontent.com/u/6914358?v=3","gravatar_id":"","url":"https://api.github.com/users/Parth-Brahmbhatt","html_url":"https://github.com/Parth-Brahmbhatt","followers_url":"https://api.github.com/users/Parth-Brahmbhatt/followers","following_url":"https://api.github.com/users/Parth-Brahmbhatt/following{/other_user}","gists_url":"https://api.github.com/users/Parth-Brahmbhatt/gists{/gist_id}","starred_url":"https://api.github.com/users/Parth-Brahmbhatt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Parth-Brahmbhatt/subscriptions","organizations_url":"https://api.github.com/users/Parth-Brahmbhatt/orgs","repos_url":"https://api.github.com/users/Parth-Brahmbhatt/repos","events_url":"https://api.github.com/users/Parth-Brahmbhatt/events{/privacy}","received_events_url":"https://api.github.com/users/Parth-Brahmbhatt/received_events","type":"User","site_admin":false},"repo":{"id":34346413,"name":"kafka","full_name":"Parth-Brahmbhatt/kafka","owner":{"login":"Parth-Brahmbhatt","id":6914358,"avatar_url":"https://avatars.githubusercontent.com/u/6914358?v=3","gravatar_id":"","url":"https://api.github.com/users/Parth-Brahmbhatt","html_url":"https://github.com/Parth-Brahmbhatt","followers_url":"https://api.github.com/users/Parth-Brahmbhatt/followers","following_url":"https://api.github.com/users/Parth-Brahmbhatt/following{/other_user}","gists_url":"https://api.github.com/users/Parth-Brahmbhatt/gists{/gist_id}","starred_url":"https://api.github.com/users/Parth-Brahmbhatt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Parth-Brahmbhatt/subscriptions","organizations_url":"https://api.github.com/users/Parth-Brahmbhatt/orgs","repos_url":"https://api.github.com/users/Parth-Brahmbhatt/repos","events_url":"https://api.github.com/users/Parth-Brahmbhatt/events{/privacy}","received_events_url":"https://api.github.com/users/Parth-Brahmbhatt/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Parth-Brahmbhatt/kafka","description":"Mirror of Apache Kafka","fork":true,"url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka","forks_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/forks","keys_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/teams","hooks_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/hooks","issue_events_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/issues/events{/number}","events_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/events","assignees_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/assignees{/user}","branches_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/branches{/branch}","tags_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/tags","blobs_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/git/refs{/sha}","trees_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/statuses/{sha}","languages_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/languages","stargazers_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/stargazers","contributors_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/contributors","subscribers_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/subscribers","subscription_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/subscription","commits_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/commits{/sha}","git_commits_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/git/commits{/sha}","comments_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/comments{/number}","issue_comment_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/issues/comments{/number}","contents_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/contents/{+path}","compare_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/merges","archive_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/downloads","issues_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/issues{/number}","pulls_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/pulls{/number}","milestones_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/milestones{/number}","notifications_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/labels{/name}","releases_url":"https://api.github.com/repos/Parth-Brahmbhatt/kafka/releases{/id}","created_at":"2015-04-21T19:00:48Z","updated_at":"2015-09-10T10:18:32Z","pushed_at":"2015-10-15T16:27:28Z","git_url":"git://github.com/Parth-Brahmbhatt/kafka.git","ssh_url":"git@github.com:Parth-Brahmbhatt/kafka.git","clone_url":"https://github.com/Parth-Brahmbhatt/kafka.git","svn_url":"https://github.com/Parth-Brahmbhatt/kafka","homepage":null,"size":23282,"stargazers_count":1,"watchers_count":1,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"0.8.2"}},"base":{"label":"apache:trunk","ref":"trunk","sha":"7915396ee891759200cb3d89bbcf3b84bf20ed6a","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":2211243,"name":"kafka","full_name":"apache/kafka","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/kafka","description":"Mirror of Apache Kafka","fork":false,"url":"https://api.github.com/repos/apache/kafka","forks_url":"https://api.github.com/repos/apache/kafka/forks","keys_url":"https://api.github.com/repos/apache/kafka/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/kafka/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/kafka/teams","hooks_url":"https://api.github.com/repos/apache/kafka/hooks","issue_events_url":"https://api.github.com/repos/apache/kafka/issues/events{/number}","events_url":"https://api.github.com/repos/apache/kafka/events","assignees_url":"https://api.github.com/repos/apache/kafka/assignees{/user}","branches_url":"https://api.github.com/repos/apache/kafka/branches{/branch}","tags_url":"https://api.github.com/repos/apache/kafka/tags","blobs_url":"https://api.github.com/repos/apache/kafka/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/kafka/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/kafka/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/kafka/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/kafka/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/kafka/languages","stargazers_url":"https://api.github.com/repos/apache/kafka/stargazers","contributors_url":"https://api.github.com/repos/apache/kafka/contributors","subscribers_url":"https://api.github.com/repos/apache/kafka/subscribers","subscription_url":"https://api.github.com/repos/apache/kafka/subscription","commits_url":"https://api.github.com/repos/apache/kafka/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/kafka/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/kafka/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/kafka/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/kafka/contents/{+path}","compare_url":"https://api.github.com/repos/apache/kafka/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/kafka/merges","archive_url":"https://api.github.com/repos/apache/kafka/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/kafka/downloads","issues_url":"https://api.github.com/repos/apache/kafka/issues{/number}","pulls_url":"https://api.github.com/repos/apache/kafka/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/kafka/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/kafka/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/kafka/labels{/name}","releases_url":"https://api.github.com/repos/apache/kafka/releases{/id}","created_at":"2011-08-15T18:06:16Z","updated_at":"2015-10-15T19:20:33Z","pushed_at":"2015-10-15T21:31:04Z","git_url":"git://github.com/apache/kafka.git","ssh_url":"git@github.com:apache/kafka.git","clone_url":"https://github.com/apache/kafka.git","svn_url":"https://github.com/apache/kafka","homepage":null,"size":36148,"stargazers_count":2057,"watchers_count":2057,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1225,"mirror_url":"git://git.apache.org/kafka.git","open_issues_count":96,"forks":1225,"open_issues":96,"watchers":2057,"default_branch":"trunk"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/kafka/pulls/300"},"html":{"href":"https://github.com/apache/kafka/pull/300"},"issue":{"href":"https://api.github.com/repos/apache/kafka/issues/300"},"comments":{"href":"https://api.github.com/repos/apache/kafka/issues/300/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/kafka/pulls/300/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/kafka/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/kafka/pulls/300/commits"},"statuses":{"href":"https://api.github.com/repos/apache/kafka/statuses/b39c4f0db0a27816b429017a26e8b470a3318438"}}}}