Skip to content

Commit 97c8dc5

Browse files
authored
Merge pull request #164 from britive/develop
Develop
2 parents 2d7e15d + 538e729 commit 97c8dc5

10 files changed

Lines changed: 154 additions & 59 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ select = [
9797

9898
[tool.ruff.lint.pylint]
9999
allow-magic-value-types = ["int", "str"]
100-
max-args = 12
100+
max-args = 14
101101
max-branches = 30
102102
max-returns = 8
103103
max-statements = 72

src/britive/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '4.4.0'
1+
__version__ = '4.5.0rc1'

src/britive/access_broker/profiles/__init__.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,25 @@ def __init__(self, britive) -> None:
1212
self.permissions = Permissions(britive)
1313
self.policies = Policies(britive)
1414

15-
def create(self, name: str, description: str = '', expiration_duration: int = 900000) -> dict:
15+
def create(
16+
self, name: str, description: str = '', expiration_duration: int = 900000, impersonation: bool = False
17+
) -> dict:
1618
"""
1719
Create a new profile.
1820
1921
:param name: Name of the profile.
2022
:param description: Description of the profile.
2123
:param expiration_duration: Expiration duration of the profile.
24+
:param impersonation: Allow impersonation of the profile.
2225
:return: Created profile.
2326
"""
2427

25-
params = {'name': name, 'description': description, 'expirationDuration': expiration_duration}
28+
params = {
29+
'name': name,
30+
'delegationEnabled': impersonation,
31+
'description': description,
32+
'expirationDuration': expiration_duration,
33+
}
2634

2735
return self.britive.post(f'{self.base_url}', json=params)
2836

@@ -46,7 +54,12 @@ def list(self) -> list:
4654
return self.britive.get(self.base_url, params={})
4755

4856
def update(
49-
self, profile_id: str, name: str = None, description: str = None, expiration_duration: int = None
57+
self,
58+
profile_id: str,
59+
name: str = None,
60+
description: str = None,
61+
expiration_duration: int = None,
62+
impersonation: bool = None,
5063
) -> dict:
5164
"""
5265
Update a profile.
@@ -55,6 +68,7 @@ def update(
5568
:param name: Name of the profile.
5669
:param description: Description of the profile.
5770
:param expiration_duration: Expiration duration of the profile.
71+
:param impersonation: Allow impersonation of the profile.
5872
:return: Updated profile.
5973
"""
6074

@@ -66,6 +80,9 @@ def update(
6680
params['description'] = description
6781
if expiration_duration:
6882
params['expirationDuration'] = expiration_duration
83+
params['delegationEnabled'] = (
84+
self.get(profile_id=profile_id).get('delegationEnabled') if impersonation is None else impersonation
85+
)
6986

7087
return self.britive.patch(f'{self.base_url}/{profile_id}', json=params)
7188

src/britive/application_management/profiles/__init__.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
from .session_attributes import SessionAttributes
88

99
creation_defaults = {
10+
'delegationEnabled': False,
11+
'description': '',
12+
'destinationUrl': '',
13+
'excludeAdminFromAdminRelatedCommunication': 'DEFAULT',
1014
'expirationDuration': 3600000,
11-
'extensionDuration': 1800000,
12-
'notificationPriorToExpiration': 300000,
1315
'extendable': False,
16+
'extensionDuration': 1800000,
1417
'extensionLimit': '1',
18+
'notificationPriorToExpiration': 300000,
1519
'status': 'active',
16-
'destinationUrl': '',
1720
'useDefaultAppUrl': True,
18-
'description': '',
1921
}
2022

2123
update_fields_to_keep: list = list(creation_defaults)
@@ -42,24 +44,25 @@ def create(self, application_id: str, name: str, **kwargs) -> dict:
4244
:param kwargs: A key/value mapping consisting of the following fields. If any/all are omitted default values
4345
will be used. The keys and default values are provided below.
4446
47+
- delegationEnabled: False
48+
- description: ''
49+
- destinationUrl: ''
50+
- excludeAdminFromAdminRelatedCommunication: 'DEFAULT'
4551
- expirationDuration: 3600000
46-
- extensionDuration: 1800000
47-
- notificationPriorToExpiration: 300000
4852
- extendable: False
53+
- extensionDuration: 1800000
4954
- extensionLimit: '1'
50-
- status: 'active'
51-
- destinationUrl: ''
52-
- useDefaultAppUrl: True
53-
- description: ''
55+
- notificationPriorToExpiration: 300000
5456
- scope: if not provided, no scopes will be applied. If provided it must follow the
5557
format listed below.
56-
5758
[
5859
{
5960
'type': 'EnvironmentGroup'|'Environment',
6061
'value':'ID'
6162
},
6263
]
64+
- status: 'active'
65+
- useDefaultAppUrl: True
6366
6467
:return: Details of the newly created profile.
6568
"""

src/britive/britive.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -181,30 +181,30 @@ def features(self) -> dict:
181181
def banner(self) -> dict:
182182
return self.get(f'{self.base_url}/banner')
183183

184-
def get(self, url, params=None) -> dict:
184+
def get(self, url, params: dict = None, headers: dict = None) -> dict:
185185
"""Internal use only."""
186186

187-
return self.__request('get', url, params=params)
187+
return self.__request('get', url, params=params, headers=headers)
188188

189-
def post(self, url, params=None, data=None, json=None) -> dict:
189+
def post(self, url, params: dict = None, data: dict = None, json: dict = None, headers: dict = None) -> dict:
190190
"""Internal use only."""
191191

192-
return self.__request('post', url, params=params, data=data, json=json)
192+
return self.__request('post', url, params=params, data=data, json=json, headers=headers)
193193

194-
def patch(self, url, params=None, data=None, json=None) -> dict:
194+
def patch(self, url, params: dict = None, data: dict = None, json: dict = None, headers: dict = None) -> dict:
195195
"""Internal use only."""
196196

197-
return self.__request('patch', url, params=params, data=data, json=json)
197+
return self.__request('patch', url, params=params, data=data, json=json, headers=headers)
198198

199-
def put(self, url, params=None, data=None, json=None) -> dict:
199+
def put(self, url, params: dict = None, data: dict = None, json: dict = None, headers: dict = None) -> dict:
200200
"""Internal use only."""
201201

202-
return self.__request('put', url, params=params, data=data, json=json)
202+
return self.__request('put', url, params=params, data=data, json=json, headers=headers)
203203

204-
def delete(self, url, params=None, data=None, json=None) -> dict:
204+
def delete(self, url, params: dict = None, data: dict = None, json: dict = None, headers: dict = None) -> dict:
205205
"""Internal use only."""
206206

207-
return self.__request('delete', url, params=params, data=data, json=json)
207+
return self.__request('delete', url, params=params, data=data, json=json, headers=headers)
208208

209209
# note - this method could be iffy in the future if the app changes the way it handles
210210
# file uploads. As of 2022-01-26 it is working fine with the "Upload SAML Metadata" action
@@ -223,11 +223,13 @@ def post_upload(self, url, params=None, files=None) -> dict:
223223
response = self.session.post(url, params=params, files=files, headers={'Content-Type': None})
224224
return handle_response(response)
225225

226-
def __request_with_exponential_backoff_and_retry(self, method, url, params, data, json) -> dict:
226+
def __request_with_exponential_backoff_and_retry(self, method, url, params, data, json, headers) -> dict:
227227
num_retries = 0
228228

229229
while num_retries <= self.retry_max_times:
230-
response = self.session.request(method, url, params=params, data=data, json=json)
230+
response = self.session.request(
231+
method, url, params=params, data=data, json=json, headers={**self.session.headers, **headers}
232+
)
231233

232234
# handle the use case of a tenant being in maintenance mode
233235
# which means we should break out of this loop early and
@@ -244,15 +246,17 @@ def __request_with_exponential_backoff_and_retry(self, method, url, params, data
244246

245247
return response
246248

247-
def __request(self, method, url, params=None, data=None, json=None) -> dict:
249+
def __request(self, method, url, params=None, data=None, json=None, headers=None) -> dict:
248250
return_data = []
249251
_pagination_type = None
250252

251253
if params is None:
252254
params = {}
255+
if headers is None:
256+
headers = {}
253257

254258
while True:
255-
response = self.__request_with_exponential_backoff_and_retry(method, url, params, data, json)
259+
response = self.__request_with_exponential_backoff_and_retry(method, url, params, data, json, headers)
256260
if response_has_no_content(response):
257261
return None
258262

src/britive/helpers/methods.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ def __init__(self, britive) -> None:
33
self.britive = britive
44

55
def get_profile_and_environment_ids_given_names(
6-
self, profile_name: str, environment_name: str, application_name: str = None
6+
self, profile_name: str, environment_name: str, application_name: str = None, headers: dict = None
77
) -> dict:
88
ids = None
99
environment_found = False
1010
profile_found = False
11-
for app in self.britive.get(f'{self.britive.base_url}/access'):
11+
for app in self.britive.get(f'{self.britive.base_url}/access', headers=headers):
1212
if application_name and app['appName'].lower() != application_name.lower():
1313
continue
1414
if not (

src/britive/helpers/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,16 @@ def source_federation_token(provider: str, tenant: Optional[str] = None, duratio
108108
* Azure System Assigned Managed Identities (azuresmi)
109109
* Azure User Assigned Managed Identities (azureumi)
110110
* Bitbucket Pipelines (bitbucket)
111+
* GCP
111112
* Github Actions (github)
112113
* Gitlab (gitlab)
113114
* spacelift.io (spacelift)
114115
115116
Any other OIDC federation provider can be used and tokens can be provided to this class for authentication
116117
to a Britive tenant. Details of how to construct these tokens can be found at https://docs.britive.com.
117118
118-
:param provider: The name of the federation provider. Valid options are `aws`, `github`, `bitbucket`,
119-
`azuresmi`, `azureumi`, `spacelift`, and `gitlab`.
119+
:param provider: The name of the federation provider. Valid options are `aws`, `azuresmi`, `azureumi`, `bitbucket`,
120+
`gcp`, `github`, `gitlab`, and `spacelift`.
120121
121122
For the AWS provider it is possible to provide a profile via value `aws-profile`. If no profile is provided
122123
then the boto3 `Session.get_credentials()` method will be used to obtain AWS credentials, which follows

src/britive/identity_management/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
class IdentityManagement:
1010
def __init__(self, britive) -> None:
11+
self.ai_identities = ServiceIdentities(britive, identity_type='AIIdentity')
1112
self.identity_attributes = IdentityAttributes(britive)
1213
self.identity_providers = IdentityProviders(britive)
1314
self.service_identities = ServiceIdentities(britive)

src/britive/identity_management/service_identities.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55

66
class ServiceIdentities:
7-
def __init__(self, britive) -> None:
7+
def __init__(self, britive, identity_type: str = 'ServiceIdentity') -> None:
88
self.britive = britive
99
self.base_url = f'{self.britive.base_url}/users'
1010
self.custom_attributes = CustomAttributes(britive)
11+
self.identity_type = identity_type
1112

1213
def list(self, filter_expression: str = None, include_tags: bool = False) -> list:
1314
"""
@@ -19,7 +20,7 @@ def list(self, filter_expression: str = None, include_tags: bool = False) -> lis
1920
:return: List of service identity records
2021
"""
2122

22-
params = {'type': 'ServiceIdentity', 'page': 0, 'size': 100}
23+
params = {'type': self.identity_type, 'page': 0, 'size': 100}
2324
if filter_expression:
2425
params['filter'] = filter_expression
2526
if include_tags:
@@ -35,7 +36,7 @@ def get(self, service_identity_id: str) -> dict:
3536
:return: Details of the specified user.
3637
"""
3738

38-
params = {'type': 'ServiceIdentity'}
39+
params = {'type': self.identity_type}
3940
return self.britive.get(f'{self.base_url}/{service_identity_id}', params=params)
4041

4142
def get_by_name(self, name: str) -> list:
@@ -70,7 +71,7 @@ def search(self, search_string: str) -> list:
7071
:return: List of user records
7172
"""
7273

73-
params = {'type': 'ServiceIdentity', 'page': 0, 'size': 100, 'searchText': search_string}
74+
params = {'type': self.identity_type, 'page': 0, 'size': 100, 'searchText': search_string}
7475

7576
return self.britive.get(self.base_url, params)
7677

@@ -87,7 +88,7 @@ def create(self, **kwargs) -> dict:
8788

8889
required_fields = ['name']
8990

90-
kwargs['type'] = 'ServiceIdentity'
91+
kwargs['type'] = self.identity_type
9192
if 'status' not in kwargs:
9293
kwargs['status'] = 'active'
9394

0 commit comments

Comments
 (0)