apache / kibble-1

Apache Kibble - a tool to collect, aggregate and visualize data about any software project
https://kibble.apache.org/
Apache License 2.0
58 stars 27 forks source link

Kibble API griefing #32

Open ghost opened 4 years ago

ghost commented 4 years ago

Theory:

Apache Kibble only supports cookie authorization for its REST API.

Attempt(s) to falsify the above:

GET http://localhost:9200/kibble_useraccount/_search?pretty HTTP/1.1
Content-Type: application/json

{
    "query": {
        "match_all": {}
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 458

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "kibble_useraccount",
        "_type": "_doc",
        "_id": "blah@blah.com",
        "_score": 1.0,
        "_source": {
          "email": "blah@blah.com",
          "password": "blah-blah-blah",
          "displayName": "Administrator",
          "organisations": [],
          "ownerships": [],
          "defaultOrganisation": "Blah",
          "verified": true,
          "userlevel": "admin",
          "token": "abdb02d7-6450-4af2-9ef3-add42907e09c"
        }
      }
    ]
  }
}

Great we have a "token". Let's see what that does:

POST http://kibble.localhost/api/org/list HTTP/1.1
Authorization: token abdb02d7-6450-4af2-9ef3-add42907e09c
Content-Type: application/json
HTTP/1.1 403 Authentication failed
Date: Wed, 27 May 2020 17:29:05 GMT
Server: gunicorn/20.0.4
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked

{
  "code": 403,
  "reason": "You must be logged in to use this API endpoint!"
}

Hmm, nothing. Let's attempt traditional authorization schemes. Note that my REST client automatically Base64 encodes 'user pass'.

POST http://kibble.localhost/api/org/list HTTP/1.1
Authorization: Basic blah@blah.com blah-blah-blah
Content-Type: application/json

and

POST http://kibble.localhost/api/org/list HTTP/1.1
Authorization: Digest blah@blah.com blah-blah-blah
Content-Type: application/json

both result in:

HTTP/1.1 403 Authentication failed
Date: Wed, 27 May 2020 17:32:52 GMT
Server: gunicorn/20.0.4
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked

{
  "code": 403,
  "reason": "You must be logged in to use this API endpoint!"
}

Hmm. Let's fiddle with kibble_uisession and see where that leads.

GET http://localhost:9200/kibble_uisession/_search?pretty HTTP/1.1
Content-Type: application/json

{
    "query": {
        "match_all": {}
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 554

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 8,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "1a50a63a-c30b-4eae-9d5d-ee3a60d5774a",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": "1a50a63a-c30b-4eae-9d5d-ee3a60d5774a",
          "timestamp": 1588490569
        }
      },
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "d111112e-0a56-4345-a826-628e82474d6b",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": "d111112e-0a56-4345-a826-628e82474d6b",
          "timestamp": 1590598956
        }
      },
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "GLhx2XEBNsvtLM3qCx7P",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": null,
          "timestamp": 1588490996
        }
      },
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "pPfjUnIBipkYliznO657",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": null,
          "timestamp": 1590528523
        }
      },
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "4322a9ac-6654-44c2-9b29-1859b2c457e4",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": "4322a9ac-6654-44c2-9b29-1859b2c457e4",
          "timestamp": 1590599702
        }
      },
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "kgDJVnIBXVmZaGAJjxn6",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": null,
          "timestamp": 1590593949
        }
      },
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "114ed171-9fe1-42fd-9b3d-b7622c438ae4",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": "114ed171-9fe1-42fd-9b3d-b7622c438ae4",
          "timestamp": 1590594038
        }
      },
      {
        "_index": "kibble_uisession",
        "_type": "_doc",
        "_id": "kQDQVnIBXVmZaGAJsipG",
        "_score": 1.0,
        "_source": {
          "cid": "blah@blah.com",
          "id": null,
          "timestamp": 1590594417
        }
      }
    ]
  }
}

Oh, hello! Let's see what gives.

POST http://kibble.localhost/api/org/list HTTP/1.1
Cookie: kibble_session=d111112e-0a56-4345-a826-628e82474d6b
Content-Type: application/json
HTTP/1.1 200 Okay
Date: Wed, 27 May 2020 17:46:40 GMT
Server: gunicorn/20.0.4
Content-Type: application/json; charset=utf-8
Connection: close
Transfer-Encoding: chunked

{
  "organisations": [
    {
      "id": "2e1c2450",
      "name": "blah1",
      "description": "blah description",
      "admins": [],
      "sourceCount": 0,
      "docCount": 16709
    },
    {
      "id": "blah2",
      "name": "blah2",
      "description": "blah description",
      "admins": [],
      "sourceCount": 0,
      "docCount": 22881
    }
  ],
  "okay": true,
  "responseTime": 0.17593073844909668
}

Conclusion: I have failed to refute the initial theory. Can anyone refute this and if not, comment on any plans available to provide proper authorization scheme for REST Clients?

Humbedooh commented 4 years ago

the token fetched from the preferences URI must currently be handed in the Kibble-Token header of the request, such as in this python example:

issues = requests.post('https://demo.kibble.apache.org/api/issue/issues',
                  headers = {
                    'Content-Type': 'application/json',
                    'Kibble-Token': TOKEN,
                  },
                  json = {
                    "page":"issues",
                    "quick":True,
                    "interval": "week",
                    "subfilter":"/(?:incubator-)?" + project + ".*\\.git",
                    "distinguish":True
                    }
                 ).json()

It would be nice if it accepted a token in the Authorization header as well, and when I'm back home, I'll work on making that happen.

Humbedooh commented 4 years ago

I'll also add that the token should be easily visible to the user, which means working on the user interface some more..