Last active
June 22, 2016 22:26
-
-
Save greggomann/1da971285c5a570a3fd6e024f90ba464 to your computer and use it in GitHub Desktop.
Tests Mesos HTTP authorization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# | |
# Usage: ./test-authz.py --master=[master_ip] --agent=[agent_ip] --good-jwt=[JWT] --bad-jwt=[JWT] | |
import requests | |
import sys | |
# These will be used to populate the mustache variables in 'config.py'. | |
# Parameters under 'all' will be used for all remotes; parameters within other | |
# keys are used for their respective remotes only. | |
# TODO: others needed: agent_id, framework_id | |
params = {} | |
params['all'] = {} | |
params['master'] = {} | |
params['agent'] = {} | |
params['all']['operator_principal'] = 'test_user' | |
params['all']['role'] = 'test_role' | |
# Load the dictionary of authorized HTTP endpoints. | |
authorized_endpoints = { | |
# Default endpoints: | |
"/files/debug": {"process": ["master", "agent"]}, | |
"/logging/toggle": {"process": ["master", "agent"]}, | |
"/metrics/snapshot": {"process": ["master", "agent"]}, | |
"/flags": {"process": ["master", "agent"]}, | |
"/frameworks": {"process": ["master"]}, | |
"/quota": {"process": ["master"]}, | |
"/roles": {"process": ["master"]}, | |
"/slaves": {"process": ["master"]}, | |
"/state": {"process": ["master"]}, | |
"/state-summary": {"process": ["master"]}, | |
"/tasks": {"process": ["master"]}, | |
"/weights": {"process": ["master"]}, | |
# Non-Default endpoints: | |
# "/files/browse": { | |
# "method": "get", | |
# "body": "path={{ file_path }}", | |
# "process": ["master", "agent"] | |
# }, | |
# | |
# "/files/download": { | |
# "method": "get", | |
# "body": "path={{ file_path }}", | |
# "process": ["master", "agent"] | |
# }, | |
# | |
# "/files/read": { | |
# "method": "get", | |
# "body": "path={{ file_path }}", | |
# "process": ["master", "agent"] | |
# }, | |
# | |
# "/create-volumes": { | |
# "method": "post", | |
# "body": ''' | |
#slaveId={{ agent_id }}&volumes='[ | |
# { | |
# "name": "disk", | |
# "type": "SCALAR", | |
# "scalar": { "value": 512 }, | |
# "role": "{{ role }}", | |
# "reservation": { | |
# "principal": "{{ operator_principal }}" | |
# }, | |
# "disk": { | |
# "persistence": { | |
# "id" : "persistent-volume-01", | |
# "principal" : "{{ operator_principal }}" | |
# }, | |
# "volume": { | |
# "mode": "RW", | |
# "container_path": "volume" | |
# } | |
# } | |
# } | |
#] | |
#''', | |
# "process": ["master"] | |
# }, | |
# | |
# "/destroy-volumes": { | |
# "method": "post", | |
# "body": ''' | |
#slaveId={{ agent_id }}&volumes='[ | |
# { | |
# "name": "disk", | |
# "type": "SCALAR", | |
# "scalar": { "value": 512 }, | |
# "role": "{{ role }}", | |
# "reservation": { | |
# "principal": "{{ operator_principal }}" | |
# }, | |
# "disk": { | |
# "persistence": { | |
# "id" : "persistent-volume-01" | |
# }, | |
# "volume": { | |
# "mode": "RW", | |
# "container_path": "volume" | |
# } | |
# } | |
# } | |
#] | |
#''', | |
# "process": ["master"] | |
# }, | |
# | |
# "/reserve": { | |
# "method": "post", | |
# "body": ''' | |
#slaveId={{ slave_id }}&resources='[ | |
# { | |
# "name": "cpus", | |
# "type": "SCALAR", | |
# "scalar": { "value": 1 }, | |
# "role": "{{ role }}", | |
# "reservation": { | |
# "principal": "{{ operator_principal }}" | |
# } | |
# } | |
#] | |
#''', | |
# "process": ["master"] | |
# }, | |
# "/unreserve": { | |
# "method": "post", | |
# "body": ''' | |
#slaveId={{ slave_id }}&resources='[ | |
# { | |
# "name": "cpus", | |
# "type": "SCALAR", | |
# "scalar": { "value": 1 }, | |
# "role": "{{ role }}", | |
# "reservation": { | |
# "principal": "{{ operator_principal }}" | |
# } | |
# } | |
#] | |
#''', | |
# "process": ["master"] | |
# }, | |
# "/teardown": { | |
# "method": "post", | |
# "body": "frameworkId={{ framework_id }}", | |
# "process": ["master"] | |
# } | |
} | |
# Substitute for moustache variables. | |
def parse_body(body, params): | |
idx_counter = 0 | |
result = '' | |
idx_begin = body.find('{{', idx_counter) | |
while idx_begin > 0: | |
result += body[idx_counter:idx_begin] | |
idx_end = body.find('}}', idx_begin) | |
idx_counter = idx_end + 2 | |
key = body[idx_begin:idx_end].strip('{} ') | |
if key not in params: | |
sys.exit('Unexpected moustache variable: ' + key) | |
result += params[key] | |
result += body[idx_counter:] | |
return result | |
remotes = {} | |
# Grab command-line arguments. | |
for argument in sys.argv[1:]: | |
trimmed = argument.strip('--') | |
arg_array = trimmed.split('=') | |
if arg_array[0] == 'master': | |
remotes['master'] = arg_array[1] | |
elif arg_array[0] == 'agent': | |
remotes['agent'] = arg_array[1] | |
elif arg_array[0] == 'good-jwt': | |
good_jwt = arg_array[1] | |
elif arg_array[0] == 'bad-jwt': | |
bad_jwt = arg_array[1] | |
superuser_auth_header = {'Authorization': good_jwt} | |
regular_auth_header = {'Authorization': bad_jwt} | |
for superuser in [True, False]: | |
headers = superuser_auth_header if superuser else regular_auth_header | |
for path, http_params in authorized_endpoints.items(): | |
http_method = http_params['method'] if 'method' in http_params else 'get' | |
for remote in http_params['process']: | |
http_body = parse_body(http_params['body'], params[remote] + params['all']) if 'body' in http_params else None | |
if http_method == 'get': | |
r = requests.get(remotes[remote] + path, http_body) | |
elif http_method == 'post': | |
r = requests.post(remotes[remote] + path, json=http_body, headers=headers) | |
else: | |
sys.exit('Unexpected HTTP request method: ' + http_method) | |
if superuser: | |
assert r.ok, 'ERROR: Authorized request for "' + remotes[remote] + path + '" returned code ' + str(r.status_code) + ' instead of 2XX' | |
print('OK - Authorized request to "' + remotes[remote] + path + '" returned OK as expected.') | |
else: | |
assert r.status_code == 403, 'ERROR: Unauthorized request for "' + remotes[remote] + path + '" returned code ' + str(r.status_code) + ' instead of 403' | |
print('OK - Unauthorized request to "' + remotes[remote] + path + '" returned 403 as expected.') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment