openapi: Specify securityScheme for the API in root level.

We used to specify the securityScheme for each REST operation seperately.
This is unecessary as the securityScheme can be specified in root level
and would be automatically applied to all operations. This also prevents
us accidentally not specifying the securityScheme for some operations and
was the case for /users/me/subscriptions PATCH endpoint. The root level
securityScheme can be also overriden in the operational level when
necessary.

swagger.io/docs/specification/authentication/#security
This commit is contained in:
Vishnu KS
2019-12-04 16:57:15 +05:30
committed by Tim Abbott
parent e08d029dde
commit c8ede33fc3
3 changed files with 29 additions and 90 deletions

View File

@@ -160,8 +160,11 @@ def generate_curl_example(endpoint: str, method: str,
lines = ["```curl"] lines = ["```curl"]
operation = endpoint + ":" + method.lower() operation = endpoint + ":" + method.lower()
operation_entry = openapi_spec.spec()['paths'][endpoint][method.lower()] operation_entry = openapi_spec.spec()['paths'][endpoint][method.lower()]
global_security = openapi_spec.spec()['security']
operation_params = operation_entry.get("parameters", []) operation_params = operation_entry.get("parameters", [])
operation_request_body = operation_entry.get("requestBody", None) operation_request_body = operation_entry.get("requestBody", None)
operation_security = operation_entry.get("security", None)
if settings.RUNNING_OPENAPI_CURL_TEST: # nocoverage if settings.RUNNING_OPENAPI_CURL_TEST: # nocoverage
from zerver.openapi.curl_param_value_generators import patch_openapi_example_values from zerver.openapi.curl_param_value_generators import patch_openapi_example_values
@@ -180,7 +183,20 @@ def generate_curl_example(endpoint: str, method: str,
api_url) api_url)
lines.append(" ".join(curl_first_line_parts)) lines.append(" ".join(curl_first_line_parts))
authentication_required = operation_entry.get("security", False) insecure_operations = ['/dev_fetch_api_key:post']
if operation_security is None:
if global_security == [{'basicAuth': []}]:
authentication_required = True
else:
raise AssertionError("Unhandled global securityScheme. Please update the code to handle this scheme.")
elif operation_security == []:
if operation in insecure_operations:
authentication_required = False
else:
raise AssertionError("Unknown operation without a securityScheme. Please update insecure_operations.")
else:
raise AssertionError("Unhandled securityScheme. Please update the code to handle this scheme.")
if authentication_required: if authentication_required:
lines.append(" -u %s:%s" % (auth_email, auth_api_key)) lines.append(" -u %s:%s" % (auth_email, auth_api_key))

View File

@@ -19,7 +19,8 @@ info:
url: https://www.apache.org/licenses/LICENSE-2.0.html url: https://www.apache.org/licenses/LICENSE-2.0.html
servers: servers:
- url: 'https://your.zulip.server/api/v1' - url: 'https://your.zulip.server/api/v1'
security:
- basicAuth: []
####################### #######################
# Endpoint definitions # Endpoint definitions
####################### #######################
@@ -38,6 +39,7 @@ paths:
type: string type: string
example: iago@zulip.com example: iago@zulip.com
required: true required: true
security: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -78,8 +80,6 @@ paths:
type: boolean type: boolean
default: false default: false
example: true example: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -171,8 +171,6 @@ paths:
type: string type: string
example: 1375801870:2942 example: 1375801870:2942
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -197,8 +195,6 @@ paths:
type: string type: string
example: Denmark example: Denmark
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -234,8 +230,6 @@ paths:
post: post:
description: Mark all the user's unread messages as read. This is often description: Mark all the user's unread messages as read. This is often
called "bankruptcy" in Zulip. called "bankruptcy" in Zulip.
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -255,8 +249,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -283,8 +275,6 @@ paths:
type: string type: string
example: new coffee machine example: new coffee machine
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -355,8 +345,6 @@ paths:
type: boolean type: boolean
default: true default: true
example: false example: false
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -515,8 +503,6 @@ paths:
type: string type: string
example: Hello example: Hello
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -565,8 +551,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -629,8 +613,6 @@ paths:
schema: schema:
type: string type: string
example: Hello example: Hello
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -669,8 +651,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -708,8 +688,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -787,8 +765,6 @@ paths:
type: string type: string
example: read example: read
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -823,8 +799,6 @@ paths:
type: string type: string
example: '**foo**' example: '**foo**'
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -886,8 +860,6 @@ paths:
type: string type: string
example: '**realm_emoji**' example: '**realm_emoji**'
required: false required: false
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -949,8 +921,6 @@ paths:
type: string type: string
example: '**realm_emoji**' example: '**realm_emoji**'
required: false required: false
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -981,8 +951,6 @@ paths:
type: string type: string
format: binary format: binary
example: /path/to/file example: /path/to/file
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1021,8 +989,6 @@ paths:
type: boolean type: boolean
default: false default: false
example: true example: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1145,8 +1111,6 @@ paths:
type: string type: string
example: newuser example: newuser
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1178,8 +1142,6 @@ paths:
type: string type: string
example: iago@zulip.com example: iago@zulip.com
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1215,8 +1177,6 @@ paths:
/users/me: /users/me:
get: get:
description: Get the requesting user's profile data from the backend. description: Get the requesting user's profile data from the backend.
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success description: Success
@@ -1319,8 +1279,6 @@ paths:
} }
delete: delete:
description: Delete the requesting user from the realm. description: Delete the requesting user from the realm.
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Bad Request description: Bad Request
@@ -1357,8 +1315,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1425,8 +1381,6 @@ paths:
type: boolean type: boolean
default: false default: false
example: true example: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1562,8 +1516,6 @@ paths:
schema: schema:
type: boolean type: boolean
example: true example: true
security:
- basicAuth: []
responses: responses:
'200_without_principals': '200_without_principals':
description: Success. description: Success.
@@ -1696,8 +1648,6 @@ paths:
type: string type: string
default: default:
example: ['ZOE@zulip.com'] example: ['ZOE@zulip.com']
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1774,8 +1724,6 @@ paths:
- remove - remove
example: add example: add
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1827,8 +1775,6 @@ paths:
type: string type: string
format: binary format: binary
example: /path/to/img.png example: /path/to/img.png
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1841,8 +1787,6 @@ paths:
/realm/emoji: /realm/emoji:
get: get:
description: Get all the custom emoji in the user's realm. description: Get all the custom emoji in the user's realm.
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1892,8 +1836,6 @@ paths:
type: object type: object
example: [{"stream_id": 1, "property": "pin_to_top", "value": true}, {"stream_id": 3, "property": "color", "value": '#f00f00'}] example: [{"stream_id": 1, "property": "pin_to_top", "value": true}, {"stream_id": 3, "property": "color", "value": '#f00f00'}]
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1929,8 +1871,6 @@ paths:
/realm/filters: /realm/filters:
get: get:
description: Fetch all the filters set up for the user's organization. description: Fetch all the filters set up for the user's organization.
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -1987,8 +1927,6 @@ paths:
type: string type: string
example: https://github.com/zulip/zulip/issues/%(id)s example: https://github.com/zulip/zulip/issues/%(id)s
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2018,8 +1956,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2111,8 +2047,6 @@ paths:
- type: integer - type: integer
default: narrow=[] default: narrow=[]
example: ['stream', 'Denmark'] example: ['stream', 'Denmark']
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2153,8 +2087,6 @@ paths:
/server_settings: /server_settings:
get: get:
description: Fetch global settings for the Zulip server. description: Fetch global settings for the Zulip server.
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2382,8 +2314,6 @@ paths:
schema: schema:
type: boolean type: boolean
example: true example: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2489,8 +2419,6 @@ paths:
type: boolean type: boolean
default: false default: false
example: true example: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2574,8 +2502,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2650,8 +2576,6 @@ paths:
example: true example: true
required: false required: false
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2705,8 +2629,6 @@ paths:
type: string type: string
example: ["iago@zulip.com", "polonius@zulip.com"] example: ["iago@zulip.com", "polonius@zulip.com"]
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2742,8 +2664,6 @@ paths:
type: integer type: integer
example: [1, 2, 3, 4] example: [1, 2, 3, 4]
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2795,8 +2715,6 @@ paths:
type: string type: string
example: The marketing team. example: The marketing team.
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2834,8 +2752,6 @@ paths:
type: integer type: integer
example: 42 example: 42
required: true required: true
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.
@@ -2867,8 +2783,6 @@ paths:
/user_groups: /user_groups:
get: get:
description: Get all user groups of the realm. description: Get all user groups of the realm.
security:
- basicAuth: []
responses: responses:
'200': '200':
description: Success. description: Success.

View File

@@ -611,6 +611,7 @@ class ModifyExampleGenerationTestCase(ZulipTestCase):
class TestCurlExampleGeneration(ZulipTestCase): class TestCurlExampleGeneration(ZulipTestCase):
spec_mock_without_examples = { spec_mock_without_examples = {
"security": [{"basicAuth": []}],
"paths": { "paths": {
"/mark_stream_as_read": { "/mark_stream_as_read": {
"post": { "post": {
@@ -641,6 +642,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
} }
spec_mock_with_invalid_method = { spec_mock_with_invalid_method = {
"security": [{"basicAuth": []}],
"paths": { "paths": {
"/endpoint": { "/endpoint": {
"brew": {} # the data is irrelevant as is should be rejected. "brew": {} # the data is irrelevant as is should be rejected.
@@ -649,6 +651,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
} # type: Dict[str, object] } # type: Dict[str, object]
spec_mock_using_object = { spec_mock_using_object = {
"security": [{"basicAuth": []}],
"paths": { "paths": {
"/endpoint": { "/endpoint": {
"get": { "get": {
@@ -673,6 +676,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
} }
spec_mock_using_param_in_path = { spec_mock_using_param_in_path = {
"security": [{"basicAuth": []}],
"paths": { "paths": {
"/endpoint/{param1}": { "/endpoint/{param1}": {
"get": { "get": {
@@ -707,6 +711,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
} }
spec_mock_using_object_without_example = { spec_mock_using_object_without_example = {
"security": [{"basicAuth": []}],
"paths": { "paths": {
"/endpoint": { "/endpoint": {
"get": { "get": {
@@ -728,6 +733,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
} }
spec_mock_using_array_without_example = { spec_mock_using_array_without_example = {
"security": [{"basicAuth": []}],
"paths": { "paths": {
"/endpoint": { "/endpoint": {
"get": { "get": {
@@ -786,6 +792,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
expected_curl_example = [ expected_curl_example = [
"```curl", "```curl",
"curl -sSX POST http://localhost:9991/api/v1/mark_stream_as_read \\", "curl -sSX POST http://localhost:9991/api/v1/mark_stream_as_read \\",
" -u BOT_EMAIL_ADDRESS:BOT_API_KEY \\",
" -d 'stream_id=1' \\", " -d 'stream_id=1' \\",
" -d 'bool_param=false'", " -d 'bool_param=false'",
"```" "```"
@@ -822,6 +829,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
expected_curl_example = [ expected_curl_example = [
'```curl', '```curl',
'curl -sSX GET -G http://localhost:9991/api/v1/endpoint \\', 'curl -sSX GET -G http://localhost:9991/api/v1/endpoint \\',
' -u BOT_EMAIL_ADDRESS:BOT_API_KEY \\',
' --data-urlencode param1=\'{"key": "value"}\'', ' --data-urlencode param1=\'{"key": "value"}\'',
'```' '```'
] ]
@@ -846,6 +854,7 @@ class TestCurlExampleGeneration(ZulipTestCase):
expected_curl_example = [ expected_curl_example = [
'```curl', '```curl',
'curl -sSX GET -G http://localhost:9991/api/v1/endpoint/35 \\', 'curl -sSX GET -G http://localhost:9991/api/v1/endpoint/35 \\',
' -u BOT_EMAIL_ADDRESS:BOT_API_KEY \\',
' --data-urlencode param2=\'{"key": "value"}\'', ' --data-urlencode param2=\'{"key": "value"}\'',
'```' '```'
] ]