From 0238ca638c0e50e5255c87d706ca9f517cfbf7cc Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Tue, 8 Jun 2021 14:10:27 -0600 Subject: [PATCH 01/11] first draft of users and grants guide, linked it into appropriate page --- docs/guides-and-resources.rst | 3 +- docs/users-grants.rst | 169 ++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 docs/users-grants.rst diff --git a/docs/guides-and-resources.rst b/docs/guides-and-resources.rst index 4bd8d0a7e..a45568573 100755 --- a/docs/guides-and-resources.rst +++ b/docs/guides-and-resources.rst @@ -18,7 +18,8 @@ Guides * :doc:`workload` - Advanced protection purpose-built for securing modern workloads to reduce the attack surface and strengthen security posture. * :doc:`reputation-override` - Manage reputation overrides for known applications, IT tools or certs. * :doc:`live-response` - Live Response allows security operators to collect information and take action on remote endpoints in real time. -* :doc:`unified-binary-store` - The unified binary store (UBS) is responsible for storing all binaries and corresponding metadata for those binaries. +* :doc:`unified-binary-store` - The unified binary store (UBS) is responsible for storing all binaries and corresponding metadata for those binaries. +* :doc:`users-grants` - Work with users and access grants. Examples -------- diff --git a/docs/users-grants.rst b/docs/users-grants.rst new file mode 100644 index 000000000..6aa858043 --- /dev/null +++ b/docs/users-grants.rst @@ -0,0 +1,169 @@ +Users and Grants +================ + +Using the Carbon Black Cloud SDK, you can work with the users in your organization, as well as their access grants +and profiles. + +Uniform Resource Names (URNs) +----------------------------- + +The various API functions that work with users and grants often make use of *uniform resource names* (URNs) that +uniquely represent various pieces of the Carbon Black Cloud environment. These pieces include: + +* **Organizations,** represented as ``psc:org:ORGKEY``, where ``ORGKEY`` is the organization's alphanumeric key value. +* **Users,** represented as ``psc:user:ORGKEY:USERID``, where ``ORGKEY`` is the organization's alphanumeric key value + and ``USERID`` is the user's numeric login ID. +* **Access roles,** represented as ``psc:role:OPT-ORGKEY:NAME``, where ``OPT-ORGKEY`` is (optionally) the alphanumeric + key value of the organization containing that role, and ``NAME`` is the name of the role. + +Most of these are dealt with for you by the Carbon Black Cloud SDK. + +Getting a List of Users +----------------------- + +We can do a query on the ``User`` object to get a list of users within the organization we're accessing. + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> query = api.select(User) + >>> user_list = list(query) + >>> for user in user_list: + ... print(f"{user.first_name} {user.last_name} (#{user.login_id}) <{user.email}>") + ... + Lysa Arryn (#2345670) + Olenna Redwyne (#2345671) + Arianne Martell (#2345672) + Jorah Mormont (#2345673) + +We can restrict the query by user IDs or E-mail addresses by using the ``user_ids()`` or ``email_addresses()`` +methods on the query object returned by ``select()`` before enumerating its results. + +Modifying a User +---------------- + +A ``User`` can be modified by changing one or more of its fields and then calling its ``save()`` method. + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> user = api.select(User, 2345672) + >>> print(f"{user.first_name} {user.last_name}") + Arianne Martell + >>> print(user.phone) + 800-555-0000 + >>> user.phone = '888-555-9753' + >>> user.save() + @ https://defense.conferdeploy.net (*) + >>> print(user.phone) + 888-555-9753 + +**Note:** A user's *role* must be changed by modifying its *access grant,* detailed below. + +Creating a New User +------------------- + +Creating a user may be done with the help of a *builder object,* which is returned from the ``User.create()`` +function. + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> builder = User.create(api) + >>> builder.set_first_name('Samwell').set_last_name('Tarly') + + >>> builder.set_email('starly@example.com').set_phone('800-555-8008') + + >>> builder.set_role('psc:role::BETA_SYSTEM_ADMIN') + + >>> builder.build() + +Alternately, you may construct a *template object* (a Python ``dict``) that contains the user's information and +create the user directly. + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> user_template = {'first_name': 'Selyse', 'last_name': 'Florent', 'email': 'sflorent@example.com', + ... 'phone': '877-555-9099', 'role_urn': 'psc:role::BETA_SYSTEM_ADMIN'} + >>> User.create(api, user_template) + +**Note:** A user that has just been created will *not* be visible in either the UI or in a ``User`` query as detailed +above, until the intended user has responded to their invitation E-mail message, activated the account, and set +a password. + +User Access Grants +------------------ + +Every user object has an *access grant* object associated with it, defining the access roles they are permitted to use. +You can use the ``grant()`` method on a ``User`` to get the grant and inspect or modify it. + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> user = api.select(User, 2345672) + >>> print(f"{user.first_name} {user.last_name}") + Arianne Martell + >>> grant = user.grant() + >>> print(grant.roles) + ['psc:role::BETA_SUPER_ADMIN'] + >>> grant.roles = ['psc:role::BETA_SYSTEM_ADMIN'] + >>> grant.save() + @ https://defense.conferdeploy.net + >>> print(grant.roles) + ['psc:role::BETA_SYSTEM_ADMIN'] + +You can see what roles you can work with by using the ``get_permitted_role_urns()`` function: + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import Grant + >>> for index, role_urn in enumerate(Grant.get_permitted_role_urns(api)): + ... print(f"{index}. {role_urn}") + ... + 0. psc:role::BETA_LEVEL_3_ANALYST + 1. psc:role::KUBERNETES_SECURITY_DATAPLANE_ONLY + 2. psc:role::ALL_AND_LR + 3. psc:role::BETA_LEVEL_1_ANALYST + 4. psc:role::BETA_SYSTEM_ADMIN + 5. psc:role::KUBERNETES_SECURITY_DATAPLANE + 6. psc:role::VIEW_ONLY + 7. psc:role::ALL + 8. psc:role::KUBERNETES_SECURITY_ADMIN_USER + 9. psc:role::BETA_SUPER_ADMIN + 10. psc:role::KUBERNETES_SECURITY_READ_ONLY_USER + 11. psc:role::CONTAINER_IMAGE_CLI_TOOL + 12. psc:role::KUBERNETES_SECURITY_DEVOPS + 13. psc:role::BETA_VIEW_ALL + 14. psc:role::KUBERNETES_SECURITY_DEVOPS_VIEW_ONLY + 15. psc:role::BETA_LEVEL_2_ANALYST + 16. psc:role::KUBERNETES_SECURITY_DEVELOPER + +Some organizations employ *access profiles* on the access grants, which allow roles for a user to be specified for +the organization and/or any child organizations. Access profiles may be accessed and manipulated through the +access grant object. + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> user = api.select(User, 3456789) + >>> grant = user.grant() + >>> for profile in grant.profiles_: + ... print(f"{profile.allowed_orgs} - {profile.roles}") + ... + ['psc:org:1A2B3C4DE'] - ['psc:role::BETA_LEVEL_3_ANALYST'] + ['psc:org:2F3G4H5JK'] - ['psc:role::BETA_LEVEL_1_ANALYST'] From 83cf91a46849fcf555bb886b6e1ee6991b4a8e9e Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Wed, 9 Jun 2021 09:53:46 -0600 Subject: [PATCH 02/11] incorporated Alex's first round of feedback --- docs/users-grants.rst | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/docs/users-grants.rst b/docs/users-grants.rst index 6aa858043..0af240429 100644 --- a/docs/users-grants.rst +++ b/docs/users-grants.rst @@ -14,7 +14,8 @@ uniquely represent various pieces of the Carbon Black Cloud environment. These * **Users,** represented as ``psc:user:ORGKEY:USERID``, where ``ORGKEY`` is the organization's alphanumeric key value and ``USERID`` is the user's numeric login ID. * **Access roles,** represented as ``psc:role:OPT-ORGKEY:NAME``, where ``OPT-ORGKEY`` is (optionally) the alphanumeric - key value of the organization containing that role, and ``NAME`` is the name of the role. + key value of the organization containing that role, and ``NAME`` is the name of the role. A role that does not have + an OPT-ORGKEY is a default/global role created for all organizations. Most of these are dealt with for you by the Carbon Black Cloud SDK. @@ -38,7 +39,7 @@ We can do a query on the ``User`` object to get a list of users within the organ Arianne Martell (#2345672) Jorah Mormont (#2345673) -We can restrict the query by user IDs or E-mail addresses by using the ``user_ids()`` or ``email_addresses()`` +We can restrict the query by user IDs or E-mail addresses by using the ``user_ids([str])`` or ``email_addresses([str])`` methods on the query object returned by ``select()`` before enumerating its results. Modifying a User @@ -52,8 +53,6 @@ A ``User`` can be modified by changing one or more of its fields and then callin >>> api = CBCloudAPI(profile='sample') >>> from cbc_sdk.platform import User >>> user = api.select(User, 2345672) - >>> print(f"{user.first_name} {user.last_name}") - Arianne Martell >>> print(user.phone) 800-555-0000 >>> user.phone = '888-555-9753' @@ -62,7 +61,7 @@ A ``User`` can be modified by changing one or more of its fields and then callin >>> print(user.phone) 888-555-9753 -**Note:** A user's *role* must be changed by modifying its *access grant,* detailed below. +**Note:** A user's *role* can only be modified by updating the user's *access grant,* detailed below. Creating a New User ------------------- @@ -97,8 +96,7 @@ create the user directly. >>> User.create(api, user_template) **Note:** A user that has just been created will *not* be visible in either the UI or in a ``User`` query as detailed -above, until the intended user has responded to their invitation E-mail message, activated the account, and set -a password. +above, until the user activates their account through the invitation E-mail message and sets a password. User Access Grants ------------------ @@ -116,14 +114,14 @@ You can use the ``grant()`` method on a ``User`` to get the grant and inspect or Arianne Martell >>> grant = user.grant() >>> print(grant.roles) - ['psc:role::BETA_SUPER_ADMIN'] - >>> grant.roles = ['psc:role::BETA_SYSTEM_ADMIN'] + ['psc:role::BETA_SYSTEM_ADMIN'] + >>> grant.roles = ['psc:role::BETA_VIEW_ONLY'] >>> grant.save() @ https://defense.conferdeploy.net >>> print(grant.roles) - ['psc:role::BETA_SYSTEM_ADMIN'] + ['psc:role::psc:role::BETA_VIEW_ONLY'] -You can see what roles you can work with by using the ``get_permitted_role_urns()`` function: +You can see what roles your API key is able to access and assign using the ``get_permitted_role_urns()`` function: :: From 5ecc039488d7b2c771f43429b14d84c0e0f7138c Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Wed, 9 Jun 2021 10:58:02 -0600 Subject: [PATCH 03/11] added a blurb about the CHILDREN URN --- docs/users-grants.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/users-grants.rst b/docs/users-grants.rst index 0af240429..e3465019b 100644 --- a/docs/users-grants.rst +++ b/docs/users-grants.rst @@ -11,6 +11,8 @@ The various API functions that work with users and grants often make use of *uni uniquely represent various pieces of the Carbon Black Cloud environment. These pieces include: * **Organizations,** represented as ``psc:org:ORGKEY``, where ``ORGKEY`` is the organization's alphanumeric key value. +* The special URN ``psc:org:ORKGEY:CHILDREN``, where where ``ORGKEY`` is the organization's alphanumeric key value, + refers to all the *child organizations* of that organization, but *not* the organization itself. * **Users,** represented as ``psc:user:ORGKEY:USERID``, where ``ORGKEY`` is the organization's alphanumeric key value and ``USERID`` is the user's numeric login ID. * **Access roles,** represented as ``psc:role:OPT-ORGKEY:NAME``, where ``OPT-ORGKEY`` is (optionally) the alphanumeric From d86a3cb68d49f98b61856f56771a9a3335255c34 Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Thu, 10 Jun 2021 16:15:23 -0600 Subject: [PATCH 04/11] profile adding function didn't work, had to make it work --- src/cbc_sdk/platform/grants.py | 31 +++++++++---------- src/cbc_sdk/platform/users.py | 5 ++- .../unit/fixtures/platform/mock_grants.py | 17 +--------- src/tests/unit/platform/test_grants.py | 2 -- src/tests/unit/platform/test_users.py | 8 ++--- 5 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/cbc_sdk/platform/grants.py b/src/cbc_sdk/platform/grants.py index f6124bc59..163fbc395 100644 --- a/src/cbc_sdk/platform/grants.py +++ b/src/cbc_sdk/platform/grants.py @@ -17,7 +17,6 @@ from cbc_sdk.errors import ApiError, NonQueryableModel import time import copy -import uuid import logging log = logging.getLogger(__name__) @@ -114,10 +113,9 @@ def _update_object(self): str: The UUID of this profile object. """ if 'profile_uuid' not in self._info: - self._info['profile_uuid'] = str(uuid.uuid4()) - log.debug("Creating a Profile object with UUID {0:s} for Grant with ID {1:s}" - .format(self._model_unique_id, self._grant._model_unique_id)) + log.debug("Creating a Profile object for Grant with ID {0:s}".format(self._grant._model_unique_id)) url = self.urlobject.format(self._cb.credentials.org_key, self._grant._model_unique_id) + print(self._info) ret = self._cb.post_object(url, self._info) else: log.debug("Updating Profile object with UUID {0:s} for Grant with ID {1:s}" @@ -198,7 +196,7 @@ def __init__(self, grant): self._cb = grant._cb self._orgs = {'allow': []} self._roles = [] - self._conditions = {'expiration': 0, 'disabled': False} + self._conditions = None self._can_manage = False def set_orgs(self, orgs_list): @@ -277,7 +275,10 @@ def set_expiration(self, expiration): Returns: ProfileBuilder: This object. """ - self._conditions['expiration'] = expiration + if self._conditions: + self._conditions['expiration'] = expiration + else: + self._conditions = {'expiration': expiration} return self def set_disabled(self, flag): @@ -290,7 +291,10 @@ def set_disabled(self, flag): Returns: ProfileBuilder: This object. """ - self._conditions['disabled'] = flag + if self._conditions: + self._conditions['disabled'] = flag + else: + self._conditions = {'disabled': flag} return self def build(self): @@ -300,7 +304,9 @@ def build(self): Returns: Profile: The new Profile object. """ - data = {'orgs': self._orgs, 'roles': self._roles, 'conditions': self._conditions} + data = {'orgs': self._orgs, 'roles': self._roles} + if self._conditions: + data['conditions'] = self._conditions profile = Grant.Profile(self._cb, self._grant, None, data) if self._grant: profile._update_object() @@ -471,8 +477,6 @@ def _update_object(self): log.debug("Creating a new Grant object for principal {0:s}".format(save_info['principal'])) save_info['profiles'] = [] for profile in self._profiles: - # presumed to be all new profiles, so create UUIDs for them - profile._info['profile_uuid'] = str(uuid.uuid4()) save_info['profiles'].append(copy.deepcopy(profile._info)) url = self.urlobject.format(self._cb.credentials.org_key) ret = self._cb.post_object(url, save_info) @@ -571,13 +575,6 @@ def create_profile(self, template=None): t = copy.deepcopy(template) if 'profile_uuid' in t: del t['profile_uuid'] - if 'conditions' not in t: - t['conditions'] = {} - if 'expiration' not in t['conditions']: - t['conditions']['expiration'] = 0 - if 'disabled' not in t['conditions']: - t['conditions']['disabled'] = False - t['can_manage'] = False profile = Grant.Profile(self._cb, self, None, t) profile._update_object() self._profiles.append(profile) diff --git a/src/cbc_sdk/platform/users.py b/src/cbc_sdk/platform/users.py index caf9f3bcf..b24f2e465 100644 --- a/src/cbc_sdk/platform/users.py +++ b/src/cbc_sdk/platform/users.py @@ -445,6 +445,7 @@ def _internal_add_profiles(self, profile_templates): """ grant = self.grant() if grant: + create_templates = [] for template in profile_templates: need_create = True for profile in grant.profiles_: @@ -454,8 +455,10 @@ def _internal_add_profiles(self, profile_templates): need_create = False break if need_create: - grant.create_profile(template) + create_templates.append(template) grant.save() + for template in create_templates: + grant.create_profile(template) else: grant_template = {'principal': self.urn, 'org_ref': self.org_urn, 'roles': [], 'principal_name': f"{self.first_name} {self.last_name}", 'profiles': profile_templates} diff --git a/src/tests/unit/fixtures/platform/mock_grants.py b/src/tests/unit/fixtures/platform/mock_grants.py index 21beba321..1717b428c 100644 --- a/src/tests/unit/fixtures/platform/mock_grants.py +++ b/src/tests/unit/fixtures/platform/mock_grants.py @@ -669,22 +669,7 @@ "disabled": True }, "can_manage": False - }, - { - "orgs": { - "allow": [ - "psc:org:test_infinity" - ], - }, - "roles": [ - "psc:role::SECOPS_ROLE_MANAGER" - ], - "conditions": { - "expiration": 0, - "disabled": False - }, - "can_manage": False - }, + } ], "org_ref": "psc:org:test", "principal_name": "Daniel Jackson", diff --git a/src/tests/unit/platform/test_grants.py b/src/tests/unit/platform/test_grants.py index 3931a7118..2f362ccb2 100644 --- a/src/tests/unit/platform/test_grants.py +++ b/src/tests/unit/platform/test_grants.py @@ -260,7 +260,6 @@ def test_create_profile_on_existing_grant(cbcsdk_mock): """Test the creation of a new profile within a grant via a builder.""" def respond_to_profile_grant(url, body, **kwargs): ret = copy.deepcopy(POST_PROFILE_IN_GRANT_RESP) - ret['profile_uuid'] = body['profile_uuid'] return ret cbcsdk_mock.mock_request('GET', '/access/v2/orgs/test/grants/psc:user:12345678:ABCDEFGH', GET_GRANT_RESP) @@ -276,7 +275,6 @@ def test_create_profile_from_template(cbcsdk_mock): """Test the creation of a new profile within a grant via a template.""" def respond_to_profile_grant(url, body, **kwargs): ret = copy.deepcopy(POST_PROFILE_IN_GRANT_RESP) - ret['profile_uuid'] = body['profile_uuid'] return ret cbcsdk_mock.mock_request('GET', '/access/v2/orgs/test/grants/psc:user:12345678:ABCDEFGH', GET_GRANT_RESP) diff --git a/src/tests/unit/platform/test_users.py b/src/tests/unit/platform/test_users.py index f2a7bc78f..46fb55f76 100644 --- a/src/tests/unit/platform/test_users.py +++ b/src/tests/unit/platform/test_users.py @@ -544,18 +544,18 @@ def test_add_profiles(cbcsdk_mock, login_id, grant_get, new_profiles, expect_put def on_put(url, body, **kwargs): nonlocal expect_put, put_was_called assert expect_put is not None - fixed_expect_put = fixup_profile_uuids(expect_put, body) - assert body == fixed_expect_put + assert body == expect_put put_was_called = True - return fixed_expect_put + return expect_put def on_profile_post(url, body, **kwargs): - nonlocal new_profiles, new_profile_count + nonlocal new_profiles, expect_new_profs, new_profile_count matched = False for template in new_profiles: matched = template_matches(body, template) or matched assert matched new_profile_count = new_profile_count + 1 + assert new_profile_count <= expect_new_profs return body cbcsdk_mock.mock_request('GET', '/appservices/v6/orgs/test/users', GET_USERS_RESP) From 14ff628d61e1487e9cb16442603a064fdf5c0569 Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Fri, 11 Jun 2021 13:47:33 -0600 Subject: [PATCH 05/11] added two more examples for adding a new profile --- docs/users-grants.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/users-grants.rst b/docs/users-grants.rst index e3465019b..62e1647fa 100644 --- a/docs/users-grants.rst +++ b/docs/users-grants.rst @@ -167,3 +167,32 @@ access grant object. ... ['psc:org:1A2B3C4DE'] - ['psc:role::BETA_LEVEL_3_ANALYST'] ['psc:org:2F3G4H5JK'] - ['psc:role::BETA_LEVEL_1_ANALYST'] + +Adding an access profile may be done via the ``create_profile()`` method on ``Grant``: + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> user = api.select(User, 3450987) + >>> grant = user.grant() + >>> builder = grant.create_profile() + >>> builder.add_org('psc:org:2F3G4H5JK').add_role('psc:role::BETA_VIEW_ALL') + + >>> profile = builder.build() + {'orgs': {'allow': ['psc:org:2F3G4H5JK']}, 'roles': ['psc:role::BETA_VIEW_ALL']} + +Or it may be added via a template object (as with ``User``): + +:: + + >>> from cbc_sdk import CBCloudAPI + >>> api = CBCloudAPI(profile='sample') + >>> from cbc_sdk.platform import User + >>> user = api.select(User, 3450987) + >>> grant = user.grant() + >>> profile_template = {'orgs': {'allow': ['psc:org:2F3G4H5JK']}, 'roles': ['psc:role::BETA_VIEW_ALL']} + >>> profile = grant.create_profile(profile_template) + {'orgs': {'allow': ['psc:org:2F3G4H5JK']}, 'roles': ['psc:role::BETA_VIEW_ALL']} + From d162783d84f4339e4017146a0b60c8cd95991b21 Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Mon, 14 Jun 2021 09:18:06 -0600 Subject: [PATCH 06/11] removed doubled word --- docs/users-grants.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/users-grants.rst b/docs/users-grants.rst index 62e1647fa..fc2cc6684 100644 --- a/docs/users-grants.rst +++ b/docs/users-grants.rst @@ -11,7 +11,7 @@ The various API functions that work with users and grants often make use of *uni uniquely represent various pieces of the Carbon Black Cloud environment. These pieces include: * **Organizations,** represented as ``psc:org:ORGKEY``, where ``ORGKEY`` is the organization's alphanumeric key value. -* The special URN ``psc:org:ORKGEY:CHILDREN``, where where ``ORGKEY`` is the organization's alphanumeric key value, +* The special URN ``psc:org:ORKGEY:CHILDREN``, where ``ORGKEY`` is the organization's alphanumeric key value, refers to all the *child organizations* of that organization, but *not* the organization itself. * **Users,** represented as ``psc:user:ORGKEY:USERID``, where ``ORGKEY`` is the organization's alphanumeric key value and ``USERID`` is the user's numeric login ID. From ce6d23e6585b3eb7b230bd349373c8111e4d6267 Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Mon, 14 Jun 2021 12:04:35 -0600 Subject: [PATCH 07/11] print not needed, remove --- src/cbc_sdk/platform/grants.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cbc_sdk/platform/grants.py b/src/cbc_sdk/platform/grants.py index 163fbc395..da0156ecd 100644 --- a/src/cbc_sdk/platform/grants.py +++ b/src/cbc_sdk/platform/grants.py @@ -115,7 +115,6 @@ def _update_object(self): if 'profile_uuid' not in self._info: log.debug("Creating a Profile object for Grant with ID {0:s}".format(self._grant._model_unique_id)) url = self.urlobject.format(self._cb.credentials.org_key, self._grant._model_unique_id) - print(self._info) ret = self._cb.post_object(url, self._info) else: log.debug("Updating Profile object with UUID {0:s} for Grant with ID {1:s}" From 0de82523f773148be5f93f7c3126bb96f7d5ffe1 Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Mon, 14 Jun 2021 13:21:28 -0600 Subject: [PATCH 08/11] rephrased wording on access profiles --- docs/users-grants.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/users-grants.rst b/docs/users-grants.rst index fc2cc6684..650b4ba94 100644 --- a/docs/users-grants.rst +++ b/docs/users-grants.rst @@ -151,9 +151,9 @@ You can see what roles your API key is able to access and assign using the ``get 15. psc:role::BETA_LEVEL_2_ANALYST 16. psc:role::KUBERNETES_SECURITY_DEVELOPER -Some organizations employ *access profiles* on the access grants, which allow roles for a user to be specified for -the organization and/or any child organizations. Access profiles may be accessed and manipulated through the -access grant object. +Users created in the Carbon Black Cloud console employ *access profiles* on the access grants, which allow roles for +a user to be specified for the organization and/or any child organizations. Access profiles may be accessed and +manipulated through the access grant object. :: From 9fdf25f23874d779e5ca0f17e1bab76454a95861 Mon Sep 17 00:00:00 2001 From: Emanuela Mitreva Date: Mon, 14 Jun 2021 20:45:46 +0300 Subject: [PATCH 09/11] [CBAPI-2626] Add the ability to provide custom session --- src/cbc_sdk/connection.py | 33 +++++++++++++++++++++++++------ src/tests/unit/test_connection.py | 16 +++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/cbc_sdk/connection.py b/src/cbc_sdk/connection.py index c20ba3384..2a5d0adb0 100644 --- a/src/cbc_sdk/connection.py +++ b/src/cbc_sdk/connection.py @@ -154,7 +154,13 @@ def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool class Connection(object): """Object that encapsulates the HTTP connection to the CB server.""" - def __init__(self, credentials, integration_name=None, timeout=None, max_retries=None, **pool_kwargs): + def __init__(self, + credentials, + integration_name=None, + timeout=None, + max_retries=None, + proxy_session=None, + **pool_kwargs): """ Initialize the Connection object. @@ -163,6 +169,7 @@ def __init__(self, credentials, integration_name=None, timeout=None, max_retries integration_name (str): The integration name being used. timeout (int): The timeout value to use for HTTP requests on this connection. max_retries (int): The maximum number of times to retry a request. + proxy_session (requests.Session) custom session to be used **pool_kwargs: Additional arguments to be used to initialize connection pooling. Raises: @@ -195,7 +202,12 @@ def __init__(self, credentials, integration_name=None, timeout=None, max_retries self.token = credentials.token self.token_header = {'X-Auth-Token': self.token, 'User-Agent': user_agent} - self.session = requests.Session() + if proxy_session: + self.session = proxy_session + credentials.use_custom_proxy_session = True + else: + self.session = requests.Session() + credentials.use_custom_proxy_session = False self._timeout = timeout @@ -215,7 +227,10 @@ def __init__(self, credentials, integration_name=None, timeout=None, max_retries self.session.mount(self.server, tls_adapter) self.proxies = {} - if credentials.ignore_system_proxy: # see https://github.com/kennethreitz/requests/issues/879 + if credentials.use_custom_proxy_session: + # get the custom session proxies + self.proxies = self.session.proxies + elif credentials.ignore_system_proxy: # see https://github.com/kennethreitz/requests/issues/879 # Unfortunately, requests will look for any proxy-related environment variables and use those anyway. The # only way to solve this without side effects, is passing in empty strings for 'http' and 'https': self.proxies = { @@ -380,13 +395,19 @@ def __init__(self, *args, **kwargs): # must be None to use MAX_RETRIES in Connection __init__ max_retries = kwargs.pop("max_retries", None) + proxy_session = kwargs.pop("proxy_session", None) pool_connections = kwargs.pop("pool_connections", 1) pool_maxsize = kwargs.pop("pool_maxsize", DEFAULT_POOLSIZE) pool_block = kwargs.pop("pool_block", DEFAULT_POOLBLOCK) - self.session = Connection(self.credentials, integration_name=integration_name, timeout=timeout, - max_retries=max_retries, pool_connections=pool_connections, - pool_maxsize=pool_maxsize, pool_block=pool_block) + self.session = Connection(self.credentials, + integration_name=integration_name, + timeout=timeout, + max_retries=max_retries, + proxy_session=proxy_session, + pool_connections=pool_connections, + pool_maxsize=pool_maxsize, + pool_block=pool_block) def raise_unless_json(self, ret, expected): """ diff --git a/src/tests/unit/test_connection.py b/src/tests/unit/test_connection.py index 2c90cd277..ffabb033e 100755 --- a/src/tests/unit/test_connection.py +++ b/src/tests/unit/test_connection.py @@ -78,6 +78,22 @@ def test_session_cert_file_and_proxies(): assert conn.proxies['https'] == 'foobie.bletch.com' +def test_session_custom_session(): + """Test to make sure custom session is passed""" + import requests + session = requests.Session() + creds = Credentials({'url': 'https://example.com', 'token': 'ABCDEFGH', 'ssl_cert_file': 'blort', + 'proxy': None}) + session.proxies = { + 'http': 'foobie.bletch.com', + 'https': 'foobie.bletch.com' + } + conn = Connection(creds, proxy_session=session) + assert conn.ssl_verify == 'blort' + assert conn.proxies['http'] == 'foobie.bletch.com' + assert conn.proxies['https'] == 'foobie.bletch.com' + + def test_session_ignore_system_proxy(): """Test to make sure the ignore system proxy parameter has the right effect.""" creds = Credentials({'url': 'https://example.com', 'token': 'ABCDEFGH', 'ignore_system_proxy': True}) From 83101a907f084f593b387c78bc28466739161e6e Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Mon, 14 Jun 2021 15:09:01 -0600 Subject: [PATCH 10/11] bump release to 1.3.1 --- README.md | 4 ++-- VERSION | 2 +- docs/changelog.rst | 12 ++++++++++++ docs/conf.py | 2 +- src/cbc_sdk/__init__.py | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b62de8f53..1128031c6 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # VMware Carbon Black Cloud Python SDK -**Latest Version:** 1.3.0 +**Latest Version:** 1.3.1
-**Release Date:** 08 June 2021 +**Release Date:** 15 June 2021 [![Coverage Status](https://coveralls.io/repos/github/carbonblack/carbon-black-cloud-sdk-python/badge.svg?t=Id6Baf)](https://coveralls.io/github/carbonblack/carbon-black-cloud-sdk-python) [![Codeship Status for carbonblack/carbon-black-cloud-sdk-python](https://app.codeship.com/projects/9e55a370-a772-0138-aae4-129773225755/status?branch=develop)](https://app.codeship.com/projects/402767) diff --git a/VERSION b/VERSION index f0bb29e76..3a3cd8cc8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.0 +1.3.1 diff --git a/docs/changelog.rst b/docs/changelog.rst index 0fb8e7671..5cf2077d1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,17 @@ Changelog ================================ +CBC SDK 1.3.1 - Released June 15, 2021 +-------------------------------- + +New Features: + +* Allow the SDK to accept a pre-configured ``Session`` object to be used for access, to get around unusual + configuration requirements. + +Bug Fixes: + +* Fix to code for adding a new access profile to a user access grant. + CBC SDK 1.3.0 - Released June 8, 2021 -------------------------------- diff --git a/docs/conf.py b/docs/conf.py index 84f0b1be9..6adbdcc56 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,7 +23,7 @@ author = 'Developer Relations' # The full version, including alpha/beta/rc tags -release = '1.3.0' +release = '1.3.1' # -- General configuration --------------------------------------------------- diff --git a/src/cbc_sdk/__init__.py b/src/cbc_sdk/__init__.py index b3fd958d9..7e0c419a6 100644 --- a/src/cbc_sdk/__init__.py +++ b/src/cbc_sdk/__init__.py @@ -4,7 +4,7 @@ __author__ = 'Carbon Black Developer Network' __license__ = 'MIT' __copyright__ = 'Copyright 2020-2021 VMware Carbon Black' -__version__ = '1.3.0' +__version__ = '1.3.1' from .rest_api import CBCloudAPI from .cache import lru From 0521222e9ecab467717e4a44f4595c0182f204a5 Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Mon, 14 Jun 2021 15:15:57 -0600 Subject: [PATCH 11/11] made message more specific --- docs/changelog.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 5cf2077d1..270ddfd2b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,12 +5,11 @@ CBC SDK 1.3.1 - Released June 15, 2021 New Features: -* Allow the SDK to accept a pre-configured ``Session`` object to be used for access, to get around unusual - configuration requirements. +* Allow the SDK to accept a pre-configured ``Session`` object to be used for access, to get around unusual configuration requirements. Bug Fixes: -* Fix to code for adding a new access profile to a user access grant. +* Fix functions in ``Grant`` object for adding a new access profile to a user access grant. CBC SDK 1.3.0 - Released June 8, 2021 --------------------------------