Skip to content

Commit db9958d

Browse files
Setting organization id in the request headers (#198)
feat: All API requests will now pass the organization context as a request header
1 parent b72f8b5 commit db9958d

4 files changed

Lines changed: 63 additions & 8 deletions

File tree

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Added
1313
`submit` and `projects`.
1414
- Deprecation warning for existing `-i` option for `projects` command.
1515
- Binder build cache step
16+
- All API requests will now pass the organization context as a request header
1617

1718
Fixed
1819
~~~~~

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ edge:
5959

6060
.. code-block:: bash
6161
62-
git clone https://github.com/transcriptic/transcriptic.git
62+
git clone https://github.com/strateos/transcriptic.git
6363
cd transcriptic
6464
pip install .[jupyter,analysis]
6565
@@ -110,7 +110,7 @@ CLI
110110
~~~
111111

112112
See the `Transcriptic Developer
113-
Documentation <https://developers.transcriptic.com/docs/getting-started-with-the-cli>`__
113+
Documentation <https://developers.strateos.com/docs/getting-started-with-the-cli>`__
114114
for detailed information about how to use this package, including
115115
learning about how to package protocols and build releases.
116116

test/config_test.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ def test_aliquot_modify(self):
9292
"https://fake.transcriptic.com/api/aliquots/23534245/modify_properties",
9393
json={"id": aliquot_id, "data": {"delete": [], "set": props}},
9494
)
95+
self.assertTrue(
96+
session.headers.get("X-Organization-Id") == connection.organization_id
97+
)
98+
self.assertTrue(
99+
session.headers.get("X-Organization-Id") == connection.env_args["org_id"]
100+
)
95101

96102
def test_signing(self):
97103
# Set up a connection with a key from a file
@@ -129,6 +135,12 @@ def test_signing(self):
129135
},
130136
)
131137
prepared_get = connection.session.prepare_request(get_request)
138+
self.assertTrue(
139+
prepared_get.headers["X-Organization-Id"] == connection.organization_id
140+
)
141+
self.assertTrue(
142+
prepared_get.headers["X-Organization-Id"] == connection.env_args["org_id"]
143+
)
132144

133145
get_sig = prepared_get.headers["authorization"]
134146
self.assertEqual(
@@ -209,6 +221,13 @@ def test_signing_auth_header_not_set_when_calling_non_api_root_endpoint(self):
209221
)
210222
prepared_get = connection.session.prepare_request(get_request)
211223
self.assertFalse("authorization" in prepared_get.headers)
224+
self.assertTrue(
225+
prepared_get.headers["X-Organization-Id"] == connection.organization_id
226+
)
227+
self.assertTrue(
228+
prepared_get.headers["X-Organization-Id"] == connection.env_args["org_id"]
229+
)
230+
self.assertTrue(prepared_get.headers["X-User-Email"] == connection.email)
212231

213232
def test_signing_request_body_already_encoded(self):
214233
# Set up a connection with a key from a file
@@ -249,6 +268,13 @@ def test_signing_request_body_already_encoded(self):
249268
)
250269
prepared_post = connection.session.prepare_request(post_request)
251270
self.assertTrue("authorization" in prepared_post.headers)
271+
self.assertTrue(
272+
prepared_post.headers["X-Organization-Id"] == connection.organization_id
273+
)
274+
self.assertTrue(
275+
prepared_post.headers["X-Organization-Id"] == connection.env_args["org_id"]
276+
)
277+
self.assertTrue(prepared_post.headers["X-User-Email"] == connection.email)
252278
self.assertTrue(isinstance(prepared_post.body, bytes))
253279

254280
# Verify that when `data` is set in the request, the authorization header is generated without error
@@ -263,6 +289,13 @@ def test_signing_request_body_already_encoded(self):
263289
)
264290
prepared_post = connection.session.prepare_request(post_request)
265291
self.assertTrue("authorization" in prepared_post.headers)
292+
self.assertTrue(
293+
prepared_post.headers["X-Organization-Id"] == connection.organization_id
294+
)
295+
self.assertTrue(
296+
prepared_post.headers["X-Organization-Id"] == connection.env_args["org_id"]
297+
)
298+
self.assertTrue(prepared_post.headers["X-User-Email"] == connection.email)
266299
self.assertFalse(isinstance(prepared_post.body, bytes))
267300

268301
def test_bearer_token(self):
@@ -296,6 +329,13 @@ def test_bearer_token(self):
296329

297330
authorization_header_value = prepared_get.headers["authorization"]
298331
self.assertEqual(bearer_token, authorization_header_value)
332+
self.assertTrue(
333+
prepared_get.headers["X-Organization-Id"] == connection.organization_id
334+
)
335+
self.assertTrue(
336+
prepared_get.headers["X-Organization-Id"] == connection.env_args["org_id"]
337+
)
338+
self.assertTrue(prepared_get.headers["X-User-Email"] == connection.email)
299339

300340
def test_bearer_token_not_set_when_calling_non_api_root_endpoint(self):
301341
"""Verify that the authorization header is NOT set when non-API root is called"""
@@ -326,6 +366,13 @@ def test_bearer_token_not_set_when_calling_non_api_root_endpoint(self):
326366
get_request = requests.Request("GET", "http://bar:5555/get")
327367
prepared_get = connection.session.prepare_request(get_request)
328368
self.assertFalse("authorization" in prepared_get.headers)
369+
self.assertTrue(
370+
prepared_get.headers["X-Organization-Id"] == connection.organization_id
371+
)
372+
self.assertTrue(
373+
prepared_get.headers["X-Organization-Id"] == connection.env_args["org_id"]
374+
)
375+
self.assertTrue(prepared_get.headers["X-User-Email"] == connection.email)
329376

330377
def test_malformed_bearer_token(self):
331378
"""Verify that an exception is thrown when a malformed JWT bearer token is provided"""
@@ -369,4 +416,10 @@ def test_user_token_supersedes_bearer_token(self):
369416
get_request = requests.Request("GET", "http://foo:5555/get")
370417
prepared_get = connection.session.prepare_request(get_request)
371418
self.assertFalse("authorization" in prepared_get.headers)
372-
self.assertTrue("X-User-Email" in prepared_get.headers)
419+
self.assertTrue(
420+
prepared_get.headers["X-Organization-Id"] == connection.organization_id
421+
)
422+
self.assertTrue(
423+
prepared_get.headers["X-Organization-Id"] == connection.env_args["org_id"]
424+
)
425+
self.assertTrue(prepared_get.headers["X-User-Email"] == connection.email)

transcriptic/config.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class Connection(object):
6868
from transcriptic.config import Connection
6969
api = Connection.from_file("~/.transcriptic")
7070
71-
For those using Jupyter notebooks on secure.transcriptic.com (beta), a
71+
For those using Jupyter notebooks on secure.strateos.com (beta), a
7272
Connection object is automatically instantiated as api.
7373
7474
.. code-block:: python
@@ -107,7 +107,7 @@ def __init__(
107107
email=None,
108108
token=None,
109109
organization_id=None,
110-
api_root="https://secure.transcriptic.com",
110+
api_root="https://secure.strateos.com",
111111
cookie=None,
112112
verbose=False,
113113
analytics=True,
@@ -120,7 +120,6 @@ def __init__(
120120
# Initialize environment args used for computing routes
121121
self.env_args = dict()
122122
self.api_root = api_root
123-
self.organization_id = organization_id
124123

125124
# Initialize session headers
126125
if session is None:
@@ -133,11 +132,12 @@ def __init__(
133132
self._rsa_key = None
134133
self._rsa_key_path = None
135134
self._rsa_secret = None
136-
# Set/Load rsa_key from arguement as string or Path
135+
# Set/Load rsa_key from argument as string or Path
137136
self.rsa_key = rsa_key
138137

139138
# NB: These many setattr calls update self.session.headers
140139
# cookie authentication is mutually exclusive from token authentication
140+
self.organization_id = organization_id
141141
if cookie:
142142
if email is not None or token is not None:
143143
warnings.warn(
@@ -218,12 +218,13 @@ def api_root(self, value):
218218
@property
219219
def organization_id(self):
220220
try:
221-
return self.env_args["org_id"]
221+
return self.session.headers["X-Organization-Id"]
222222
except (NameError, KeyError):
223223
raise ValueError("organization_id is not set.")
224224

225225
@organization_id.setter
226226
def organization_id(self, value):
227+
self.update_headers(**{"X-Organization-Id": value})
227228
self.update_environment(org_id=value)
228229

229230
@property

0 commit comments

Comments
 (0)