Skip to content

Commit 7fd688d

Browse files
authored
[ALERT] Fix for breaking changes introduced by Bearer Token work (#121)
* critical fix to bearer token breakage * corrected issue with header initialization in json helper * removed else exception, no auth is passed by internal algo API processing * added a test case tracking authorization required server responses and system handling no auth provided gracefully * added a false flag to actually invalidate environment variables for client auth * cleaned up client, used environment variable manipulation in the test suite * removing problematic server test
1 parent 6d35bbc commit 7fd688d

File tree

3 files changed

+44
-26
lines changed

3 files changed

+44
-26
lines changed

Algorithmia/client.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,16 @@ class Client(object):
2424
requestSession = None
2525
bearerToken = None
2626

27-
28-
def __init__(self, apiKey = None, apiAddress = None, caCert = None, bearerToken=None):
27+
def __init__(self, apiKey=None, apiAddress=None, caCert=None, bearerToken=None):
2928
# Override apiKey with environment variable
3029
config = None
3130
self.requestSession = requests.Session()
3231
if apiKey is None and 'ALGORITHMIA_API_KEY' in os.environ:
3332
apiKey = os.environ['ALGORITHMIA_API_KEY']
34-
if apiKey is None:
35-
if bearerToken is None and 'ALGORITHMIA_BEARER_TOKEN' in os.environ:
36-
bearerToken = os.environ['ALGORITHMIA_BEARER_TOKEN']
37-
self.bearerToken = bearerToken
33+
elif bearerToken is None and 'ALGORITHMIA_BEARER_TOKEN' in os.environ:
34+
bearerToken = os.environ['ALGORITHMIA_BEARER_TOKEN']
3835

36+
self.bearerToken = bearerToken
3937
self.apiKey = apiKey
4038
if apiAddress is not None:
4139
self.apiAddress = apiAddress
@@ -225,8 +223,8 @@ def postJsonHelper(self, url, input_object, parse_response_as_json=True, **query
225223
headers = {}
226224
if self.apiKey is not None:
227225
headers['Authorization'] = self.apiKey
228-
else:
229-
headers['Authorization'] = "Bearer "+ self.bearerToken
226+
elif self.bearerToken is not None:
227+
headers['Authorization'] = 'Bearer ' + self.bearerToken
230228

231229
input_json = None
232230
if input_object is None:
@@ -254,42 +252,42 @@ def getHelper(self, url, **query_parameters):
254252
headers = {}
255253
if self.apiKey is not None:
256254
headers['Authorization'] = self.apiKey
257-
else:
258-
headers['Authorization'] = 'Bearer '+ self.bearerToken
255+
elif self.bearerToken is not None:
256+
headers['Authorization'] = 'Bearer ' + self.bearerToken
259257
return self.requestSession.get(self.apiAddress + url, headers=headers, params=query_parameters)
260258

261259
def getStreamHelper(self, url, **query_parameters):
262260
headers = {}
263261
if self.apiKey is not None:
264262
headers['Authorization'] = self.apiKey
265-
else:
266-
headers['Authorization'] = 'Bearer '+ self.bearerToken
263+
elif self.bearerToken is not None:
264+
headers['Authorization'] = 'Bearer ' + self.bearerToken
267265
return self.requestSession.get(self.apiAddress + url, headers=headers, params=query_parameters, stream=True)
268266

269267
def patchHelper(self, url, params):
270268
headers = {'content-type': 'application/json'}
271269
if self.apiKey is not None:
272270
headers['Authorization'] = self.apiKey
273-
else:
274-
headers['Authorization'] = 'Bearer '+ self.bearerToken
271+
elif self.bearerToken is not None:
272+
headers['Authorization'] = 'Bearer ' + self.bearerToken
275273
return self.requestSession.patch(self.apiAddress + url, headers=headers, data=json.dumps(params))
276274

277275
# Used internally to get http head result
278276
def headHelper(self, url):
279277
headers = {}
280278
if self.apiKey is not None:
281279
headers['Authorization'] = self.apiKey
282-
else:
283-
headers['Authorization'] = 'Bearer '+ self.bearerToken
280+
elif self.bearerToken is not None:
281+
headers['Authorization'] = 'Bearer ' + self.bearerToken
284282
return self.requestSession.head(self.apiAddress + url, headers=headers)
285283

286284
# Used internally to http put a file
287285
def putHelper(self, url, data):
288286
headers = {}
289287
if self.apiKey is not None:
290288
headers['Authorization'] = self.apiKey
291-
else:
292-
headers['Authorization'] = 'Bearer '+ self.bearerToken
289+
elif self.bearerToken is not None:
290+
headers['Authorization'] = 'Bearer ' + self.bearerToken
293291
if isJson(data):
294292
headers['Content-Type'] = 'application/json'
295293

@@ -303,8 +301,8 @@ def deleteHelper(self, url):
303301
headers = {}
304302
if self.apiKey is not None:
305303
headers['Authorization'] = self.apiKey
306-
else:
307-
headers['Authorization'] = 'Bearer '+ self.bearerToken
304+
elif self.bearerToken is not None:
305+
headers['Authorization'] = 'Bearer ' + self.bearerToken
308306
response = self.requestSession.delete(self.apiAddress + url, headers=headers)
309307
if response.reason == "No Content":
310308
return response
@@ -364,11 +362,12 @@ def freeze(self, manifest_path, manifest_output_dir="."):
364362
required_files[i]['md5_checksum'] = md5_checksum
365363
lock_md5_checksum = md5_for_str(str(manifest_file))
366364
manifest_file['lock_checksum'] = lock_md5_checksum
367-
with open(manifest_output_dir+'/'+'model_manifest.json.freeze', 'w') as f:
365+
with open(manifest_output_dir + '/' + 'model_manifest.json.freeze', 'w') as f:
368366
json.dump(manifest_file, f)
369367
else:
370368
print("Expected to find a model_manifest.json file, none was discovered in working directory")
371369

370+
372371
def isJson(myjson):
373372
try:
374373
json_object = json.loads(myjson)

Test/api/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ def _start_webserver():
2323
async def process_algo_req(request: Request, username, algoname, output: Optional[str] = None):
2424
metadata = {"request_id": "req-55c0480d-6af3-4a21-990a-5c51d29f5725", "duration": 0.000306774}
2525
content_type = request.headers['Content-Type']
26+
auth = request.headers.get('Authorization', None)
27+
if auth is None:
28+
return {"error": {"message": "authorization required"}}
2629
request = await request.body()
2730
if output and output == "void":
2831
return {"async": "abcd123", "request_id": "req-55c0480d-6af3-4a21-990a-5c51d29f5725"}

Test/client_test.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99

1010
import unittest
1111
import Algorithmia
12+
from Algorithmia.errors import AlgorithmException
1213
from uuid import uuid4
1314

1415
if sys.version_info.major >= 3:
1516
unicode = str
1617

18+
1719
class ClientDummyTest(unittest.TestCase):
1820
@classmethod
1921
def setUpClass(cls):
@@ -71,7 +73,6 @@ def test_get_build_logs(self):
7173

7274
self.assertTrue(u'error' not in result)
7375

74-
7576
def test_edit_org(self):
7677
org_name = "a_myOrg84"
7778

@@ -138,7 +139,7 @@ def test_algorithm_programmatic_create_process(self):
138139
algorithm_name = "algo_e2d_test"
139140
payload = "John"
140141
expected_response = "hello John"
141-
full_path = "a_Mrtest/" + algorithm_name
142+
full_path = "a_Mrtest/" + algorithm_name
142143
details = {
143144
"summary": "Example Summary",
144145
"label": "QA",
@@ -189,6 +190,23 @@ def test_algorithm_programmatic_create_process(self):
189190
response = created_algo.info(git_hash)
190191

191192
self.assertEqual(response.version_info.semantic_version, "0.1.0", "information is incorrect")
193+
194+
def test_no_auth_client(self):
195+
196+
key = os.environ.get('ALGORITHMIA_API_KEY', "")
197+
if key != "":
198+
del os.environ['ALGORITHMIA_API_KEY']
199+
200+
client = Algorithmia.client(api_address="http://localhost:8080")
201+
error = None
202+
try:
203+
client.algo("demo/hello").pipe("world")
204+
except Exception as e:
205+
error = e
206+
finally:
207+
os.environ['ALGORITHMIA_API_KEY'] = key
208+
self.assertEqual(str(error), str(AlgorithmException(message="authorization required", stack_trace=None, error_type=None)))
209+
192210
else:
193211
class ClientTest(unittest.TestCase):
194212
seed(datetime.now().microsecond)
@@ -201,7 +219,7 @@ class ClientTest(unittest.TestCase):
201219
def setUp(self):
202220
self.admin_api_key = unicode(os.environ.get('ALGORITHMIA_A_KEY'))
203221
self.regular_api_key = unicode(os.environ.get('ALGORITHMIA_API_KEY'))
204-
222+
205223
self.admin_username = self.admin_username + str(int(random() * 10000))
206224
self.admin_org_name = self.admin_org_name + str(int(random() * 10000))
207225
self.admin_client = Algorithmia.client(api_address="https://test.algorithmia.com",
@@ -400,7 +418,5 @@ def test_algorithm_programmatic_create_process(self):
400418
def test_algo_freeze(self):
401419
self.regular_client.freeze("Test/resources/manifests/example_manifest.json", "Test/resources/manifests")
402420

403-
404-
405421
if __name__ == '__main__':
406422
unittest.main()

0 commit comments

Comments
 (0)