)]}'
{"etc/zuul.conf-sample":[{"author":{"_account_id":9311,"name":"Tristan Cacqueray","email":"tdecacqu@redhat.com","username":"tristanC"},"change_message_id":"e14df181087be995839ee88619e7cd0e78ce5347","unresolved":false,"context_lines":[{"line_number":40,"context_line":"static_cache_expiry\u003d0"},{"line_number":41,"context_line":"status_url\u003dhttps://zuul.example.com/status"},{"line_number":42,"context_line":"enable_admin_endpoints\u003dFalse"},{"line_number":43,"context_line":"JWTsecret\u003dNoDanaOnlyZuul"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"[connection gerrit]"},{"line_number":46,"context_line":"driver\u003dgerrit"}],"source_content_type":"application/octet-stream","patch_set":15,"id":"5f7c97a3_f152cc35","line":43,"updated":"2018-07-20 02:27:08.000000000","message":"Shouldn\u0027t the admin endpoint be enabled when a JWTsecret is set? It seems like the \u0027enable_admin_endpoints\u0027 option is redundant and the option may be removed.","commit_id":"24212be0a07b4b94c8ba6f28af47a4aceee502d1"}],"releasenotes/notes/admin_web_api-1331c81070a3e67f.yaml":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"f901a51b0209f7b80e9fe8bda4b60043dafdf4b1","unresolved":false,"context_lines":[{"line_number":13,"context_line":"    Allow an operator to configure multiple authenticators in Zuul Web Server\u0027s"},{"line_number":14,"context_line":"    configuration. Authenticators define ways to validate JWTs issued by a given"},{"line_number":15,"context_line":"    Identity Provider, and sometimes to generate tokens as well if the signing"},{"line_number":16,"context_line":"    secret is known."},{"line_number":17,"context_line":"upgrade:"},{"line_number":18,"context_line":"  - |"},{"line_number":19,"context_line":"    The \"autohold\", \"dequeue\" and \"enqueue\" endpoints are deactivated by default."}],"source_content_type":"text/x-yaml","patch_set":60,"id":"9fb8cfa7_12938e51","line":16,"updated":"2019-06-18 16:56:23.000000000","message":"Let\u0027s just summarize this as a single feature addition -- probably the first entry is enough (but maybe add the endpoints as examples of what can be done?).  This is interpreted as sphinx as part of the docs, so you can do an internal link to the documentation.\n\nWe don\u0027t want this to be too long, otherwise people won\u0027t read it.","commit_id":"601f2e4d20066124d2bfd9ed578861b401013291"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"f901a51b0209f7b80e9fe8bda4b60043dafdf4b1","unresolved":false,"context_lines":[{"line_number":35,"context_line":"    and pose potential resources problems with Nodepool if the ``autohold`` feature"},{"line_number":36,"context_line":"    is abused, leading to a significant number of nodes remaining in \"hold\" state for"},{"line_number":37,"context_line":"    extended periods of time. As always, \"with great power comes great responsibility\""},{"line_number":38,"context_line":"    and Tokens should be handed over with discernment."}],"source_content_type":"text/x-yaml","patch_set":60,"id":"9fb8cfa7_b297223b","line":38,"updated":"2019-06-18 16:56:23.000000000","message":"I don\u0027t think we need either the security or upgrade notes.  We usually use \"upgrade\" for telling people about actions which may need to be performed in order to upgrade, but this is disabled by default, so people will get the current behavior unless they opt-in to the new feature.  Similarly, \"security\" is usually where we let people know about vulnerabilities, but since this is disabled by default, there won\u0027t be any at this point.","commit_id":"601f2e4d20066124d2bfd9ed578861b401013291"}],"tests/unit/test_web.py":[{"author":{"_account_id":16068,"name":"Tobias Henkel","email":"tobias.henkel@bmw.de","username":"tobias.henkel"},"change_message_id":"354eb91bf2471d1a8f088dfbbc3d45cd611162b2","unresolved":false,"context_lines":[{"line_number":1124,"context_line":"                  \u0027count\u0027: 1,"},{"line_number":1125,"context_line":"                  \u0027reason\u0027: \u0027because\u0027,"},{"line_number":1126,"context_line":"                  \u0027node_hold_expiration\u0027: 36000})"},{"line_number":1127,"context_line":"        self.assertEqual(400, resp.status_code)"},{"line_number":1128,"context_line":"        resp \u003d self.post_url("},{"line_number":1129,"context_line":"            \"api/tenant/tenant-one/project/org/project/enqueue\","},{"line_number":1130,"context_line":"            json\u003d{\u0027trigger\u0027: \u0027gerrit\u0027,"}],"source_content_type":"text/x-python","patch_set":61,"id":"9fb8cfa7_34276767","line":1127,"range":{"start_line":1127,"start_character":25,"end_line":1127,"end_character":28},"updated":"2019-06-21 07:09:10.000000000","message":"Should we get 400 (bad request) or 401 (unauthorized) without token?","commit_id":"7926e09452df44aeed3946d79f6cc01f7a906953"}],"zuul/web/__init__.py":[{"author":{"_account_id":6889,"name":"Fabien Boucher","email":"fboucher@redhat.com","username":"fabien-boucher"},"change_message_id":"f762393315280c5c046f42b01946159d88577b93","unresolved":false,"context_lines":[{"line_number":604,"context_line":"        if cherrypy.request.method !\u003d \u0027POST\u0027:"},{"line_number":605,"context_line":"            raise cherrypy.HTTPError(405)"},{"line_number":606,"context_line":"        # AuthN/AuthZ"},{"line_number":607,"context_line":"        rawToken \u003d cherrypy.request.headers[\u0027Authorization\u0027][len(\u0027Bearer \u0027):]"},{"line_number":608,"context_line":"        try:"},{"line_number":609,"context_line":"            uid, authz \u003d self.zuulweb.auths.authenticate(rawToken)"},{"line_number":610,"context_line":"        except exceptions.AuthTokenException as e:"},{"line_number":611,"context_line":"            for header, contents in e.getAdditionalHeaders().items():"},{"line_number":612,"context_line":"                cherrypy.response.headers[header] \u003d contents"},{"line_number":613,"context_line":"            cherrypy.response.status \u003d e.HTTPError"},{"line_number":614,"context_line":"            return \u0027\u003ch1\u003e%s\u003c/h1\u003e\u0027 % e.error_description"},{"line_number":615,"context_line":"        # TODO plug an actual authorization mechanism, for now rely on token"},{"line_number":616,"context_line":"        # content"},{"line_number":617,"context_line":"        if not is_authorized(uid, \u0027enqueue\u0027, tenant, project, authz):"}],"source_content_type":"text/x-python","patch_set":37,"id":"9fdfeff1_58548321","line":614,"range":{"start_line":607,"start_character":0,"end_line":614,"end_character":54},"updated":"2019-02-11 10:26:28.000000000","message":"Could be extracted in a dedicated method and re-used.","commit_id":"0b71f9df8a08fe609afbe3dd9d36859b45a864ad"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"16343ef8de6ef6c1b623788fa51497862377099c","unresolved":false,"context_lines":[{"line_number":85,"context_line":"        raise cherrypy.HTTPError("},{"line_number":86,"context_line":"            400,"},{"line_number":87,"context_line":"            \u0027Invalid Authorization header format: \u0027"},{"line_number":88,"context_line":"            \u0027must start with \"Bearer\"\u0027)"},{"line_number":89,"context_line":"    if not token.lower().startswith(\u0027bearer \u0027):"},{"line_number":90,"context_line":"        raise cherrypy.HTTPError("},{"line_number":91,"context_line":"            400,"}],"source_content_type":"text/x-python","patch_set":61,"id":"7faddb67_fa9226f6","line":88,"updated":"2019-07-09 15:47:01.000000000","message":"Later patchsets switch to 401.","commit_id":"7926e09452df44aeed3946d79f6cc01f7a906953"},{"author":{"_account_id":16068,"name":"Tobias Henkel","email":"tobias.henkel@bmw.de","username":"tobias.henkel"},"change_message_id":"354eb91bf2471d1a8f088dfbbc3d45cd611162b2","unresolved":false,"context_lines":[{"line_number":82,"context_line":"    bearer token.\"\"\""},{"line_number":83,"context_line":"    token \u003d cherrypy.request.headers.get(\u0027Authorization\u0027, None)"},{"line_number":84,"context_line":"    if token is None:"},{"line_number":85,"context_line":"        raise cherrypy.HTTPError("},{"line_number":86,"context_line":"            400,"},{"line_number":87,"context_line":"            \u0027Invalid Authorization header format: \u0027"},{"line_number":88,"context_line":"            \u0027must start with \"Bearer\"\u0027)"},{"line_number":89,"context_line":"    if not token.lower().startswith(\u0027bearer \u0027):"},{"line_number":90,"context_line":"        raise cherrypy.HTTPError("},{"line_number":91,"context_line":"            400,"}],"source_content_type":"text/x-python","patch_set":61,"id":"9fb8cfa7_f4ceaf81","line":88,"range":{"start_line":85,"start_character":0,"end_line":88,"end_character":39},"updated":"2019-06-21 07:09:10.000000000","message":"This means there was no Authorization header at all so shouldn\u0027t we respond with 401 unauthorized instead of bad request here?","commit_id":"7926e09452df44aeed3946d79f6cc01f7a906953"},{"author":{"_account_id":16068,"name":"Tobias Henkel","email":"tobias.henkel@bmw.de","username":"tobias.henkel"},"change_message_id":"568f81821144e3a8050deb259ff5962e5ff8ecdd","unresolved":false,"context_lines":[{"line_number":82,"context_line":"    bearer token.\"\"\""},{"line_number":83,"context_line":"    token \u003d cherrypy.request.headers.get(\u0027Authorization\u0027, None)"},{"line_number":84,"context_line":"    if token is None:"},{"line_number":85,"context_line":"        raise cherrypy.HTTPError("},{"line_number":86,"context_line":"            400,"},{"line_number":87,"context_line":"            \u0027Invalid Authorization header format: \u0027"},{"line_number":88,"context_line":"            \u0027must start with \"Bearer\"\u0027)"},{"line_number":89,"context_line":"    if not token.lower().startswith(\u0027bearer \u0027):"},{"line_number":90,"context_line":"        raise cherrypy.HTTPError("},{"line_number":91,"context_line":"            400,"}],"source_content_type":"text/x-python","patch_set":61,"id":"9fb8cfa7_abe69515","line":88,"range":{"start_line":85,"start_character":0,"end_line":88,"end_character":39},"in_reply_to":"9fb8cfa7_6f62ea18","updated":"2019-06-21 09:31:17.000000000","message":"According to rfc 6750 my understanding is that this should be 401 [1]:\n\n   For example, in response to a protected resource request without\n   authentication:\n\n     HTTP/1.1 401 Unauthorized\n     WWW-Authenticate: Bearer realm\u003d\"example\"\n\nWhile reading this I guess we should also send the \u0027WWW-Authenticate\u0027 headers for all of those 40x errors.\n\n[1] https://tools.ietf.org/html/rfc6750#section-3","commit_id":"7926e09452df44aeed3946d79f6cc01f7a906953"},{"author":{"_account_id":7186,"name":"Matthieu Huin","email":"mhuin@redhat.com","username":"mhu"},"change_message_id":"6abd242bd5dd182fb39e923860416df2ec1cafd2","unresolved":false,"context_lines":[{"line_number":82,"context_line":"    bearer token.\"\"\""},{"line_number":83,"context_line":"    token \u003d cherrypy.request.headers.get(\u0027Authorization\u0027, None)"},{"line_number":84,"context_line":"    if token is None:"},{"line_number":85,"context_line":"        raise cherrypy.HTTPError("},{"line_number":86,"context_line":"            400,"},{"line_number":87,"context_line":"            \u0027Invalid Authorization header format: \u0027"},{"line_number":88,"context_line":"            \u0027must start with \"Bearer\"\u0027)"},{"line_number":89,"context_line":"    if not token.lower().startswith(\u0027bearer \u0027):"},{"line_number":90,"context_line":"        raise cherrypy.HTTPError("},{"line_number":91,"context_line":"            400,"}],"source_content_type":"text/x-python","patch_set":61,"id":"9fb8cfa7_4be039cd","line":88,"range":{"start_line":85,"start_character":0,"end_line":88,"end_character":39},"in_reply_to":"9fb8cfa7_abe69515","updated":"2019-06-21 09:48:53.000000000","message":"The realm is authenticator-bound by design, but I can add a default setting to pick a default realm when no authentication is found in the request.","commit_id":"7926e09452df44aeed3946d79f6cc01f7a906953"},{"author":{"_account_id":7186,"name":"Matthieu Huin","email":"mhuin@redhat.com","username":"mhu"},"change_message_id":"db6d402487201f3d4fae611e42d473f11a2bd333","unresolved":false,"context_lines":[{"line_number":82,"context_line":"    bearer token.\"\"\""},{"line_number":83,"context_line":"    token \u003d cherrypy.request.headers.get(\u0027Authorization\u0027, None)"},{"line_number":84,"context_line":"    if token is None:"},{"line_number":85,"context_line":"        raise cherrypy.HTTPError("},{"line_number":86,"context_line":"            400,"},{"line_number":87,"context_line":"            \u0027Invalid Authorization header format: \u0027"},{"line_number":88,"context_line":"            \u0027must start with \"Bearer\"\u0027)"},{"line_number":89,"context_line":"    if not token.lower().startswith(\u0027bearer \u0027):"},{"line_number":90,"context_line":"        raise cherrypy.HTTPError("},{"line_number":91,"context_line":"            400,"}],"source_content_type":"text/x-python","patch_set":61,"id":"9fb8cfa7_6f62ea18","line":88,"range":{"start_line":85,"start_character":0,"end_line":88,"end_character":39},"in_reply_to":"9fb8cfa7_f4ceaf81","updated":"2019-06-21 08:54:52.000000000","message":"This is open for debate: my understanding of https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1 is that a missing Authorization header is a malformed request, so the answer should be a 400.\n\nNevertheless the error message is incorrect, I\u0027ll fix it.","commit_id":"7926e09452df44aeed3946d79f6cc01f7a906953"}]}
