Skip to content

Commit 797be12

Browse files
committed
fix: policy attachents
1 parent 9c673d1 commit 797be12

File tree

3 files changed

+144
-38
lines changed

3 files changed

+144
-38
lines changed

docs/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# Manual change log
22

33
## Latest
4+
45
- fix: certificate_databases : python syntax (indentation)
6+
- fix: policy_attachments.py : idempotency and handle applications correctly
7+
-
58

69
## 2025.6.3.0
710

ibmsecurity/isam/aac/access_control/policy_attachments.py

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ def get(isamAppliance, server, resourceUri, check_mode=False, force=False):
2828
check_mode=check_mode,
2929
force=force,
3030
)
31-
resource_id = ret_obj["data"]
31+
resource_id = ret_obj.get("data", {})
3232

3333
if resource_id == {}:
3434
logger.info(
35-
f"Resource {server}/{resourceUri} had no match, skipping retrieval."
35+
f"Resource {server}{resourceUri} had no match, skipping retrieval."
3636
)
3737
return isamAppliance.create_return_object()
3838
else:
@@ -57,7 +57,7 @@ def get_attachments(isamAppliance, server, resourceUri, check_mode=False, force=
5757

5858
if resource_id == {}:
5959
logger.info(
60-
f"Resource {server}/{resourceUri} had no match, skipping retrieval."
60+
f"Resource {server}{resourceUri} had no match, skipping retrieval."
6161
)
6262
return isamAppliance.create_return_object()
6363
else:
@@ -77,10 +77,11 @@ def search(isamAppliance, server, resourceUri, force=False, check_mode=False):
7777
for obj in ret_obj["data"]:
7878
if obj["resourceUri"] == resourceUri and obj["server"] == server:
7979
logger.info(
80-
f"Found server/resourceUri {server}/{resourceUri} id: {obj['id']}"
80+
f"Found server/resourceUri {server}{resourceUri} id: {obj['id']}"
8181
)
8282
return_obj["data"] = obj["id"]
8383
return_obj["rc"] = 0
84+
return return_obj
8485

8586
return return_obj
8687

@@ -144,38 +145,55 @@ def config(
144145
{'name': '<definition name>', 'type': 'definition'}]
145146
"""
146147
warnings = []
147-
if force is False:
148-
ret_obj = search(isamAppliance, server, resourceUri)
148+
ret_obj = search(isamAppliance, server, resourceUri)
149149

150-
if force is True or ret_obj["data"] == {}:
151-
json_data = {"server": server, "resourceUri": resourceUri}
152-
if policyType is not None:
153-
if tools.version_compare(isamAppliance.facts["version"], "9.0.6.0") < 0:
154-
warnings.append(
155-
f"Appliance at version: {isamAppliance.facts['version']}, policyType: {policyType} is not supported. Needs 9.0.6.0 or higher. Ignoring policyType for this call."
156-
)
157-
else:
158-
json_data["type"] = policyType
150+
json_data = {"server": server, "resourceUri": resourceUri}
151+
if policyType is not None:
152+
if tools.version_compare(isamAppliance.facts["version"], "9.0.6.0") < 0:
153+
warnings.append(
154+
f"Appliance at version: {isamAppliance.facts['version']}, policyType: {policyType} is not supported. Needs 9.0.6.0 or higher. Ignoring policyType for this call."
155+
)
156+
else:
157+
json_data["type"] = policyType
158+
159+
json_data["policies"] = _convert_policy_name_to_id(isamAppliance, policies)
160+
if policyCombiningAlgorithm is not None:
161+
json_data["policyCombiningAlgorithm"] = policyCombiningAlgorithm
162+
if cache is not None:
163+
if tools.version_compare(isamAppliance.facts["version"], "9.0.3.0") < 0:
164+
warnings.append(
165+
f"Appliance at version: {isamAppliance.facts['version']}, cache: {cache} is not supported. Needs 9.0.3.0 or higher. Ignoring cache for this call."
166+
)
167+
else:
168+
json_data["cache"] = int(cache)
159169

160-
json_data["policies"] = _convert_policy_name_to_id(isamAppliance, policies)
161-
if policyCombiningAlgorithm is not None:
162-
json_data["policyCombiningAlgorithm"] = policyCombiningAlgorithm
163-
if cache is not None:
164-
if tools.version_compare(isamAppliance.facts["version"], "9.0.3.0") < 0:
165-
warnings.append(
166-
f"Appliance at version: {isamAppliance.facts['version']}, cache: {cache} is not supported. Needs 9.0.3.0 or higher. Ignoring cache for this call."
167-
)
168-
else:
169-
json_data["cache"] = int(cache)
170-
if check_mode is True:
170+
if force or ret_obj.get("data", {}) == {}:
171+
if check_mode:
171172
return isamAppliance.create_return_object(changed=True, warnings=warnings)
172173
else:
173174
return isamAppliance.invoke_post(
174175
"Configure a resource", uri, json_data, warnings=warnings
175176
)
176-
177-
return isamAppliance.create_return_object()
178-
177+
else:
178+
# Idempotency check
179+
logger.debug(f"Idempotency check for {server}{resourceUri}")
180+
curConfig = get(isamAppliance, server, resourceUri)
181+
curConfig = curConfig.get("data", {})
182+
# Need to get rid of lastmodified and name in each policy
183+
_policies = list(map(lambda item: item.pop('lastmodified', None), curConfig.get("policies", [])))
184+
_policies = list(map(lambda item: item.pop('name', None), curConfig.get("policies", [])))
185+
if tools.json_equals(curConfig, json_data):
186+
# No updates needed
187+
return isamAppliance.create_return_object()
188+
else:
189+
if check_mode:
190+
return isamAppliance.create_return_object(changed=True, warnings=warnings)
191+
else:
192+
# delete and add again
193+
delete(isamAppliance, server, resourceUri)
194+
return isamAppliance.invoke_post(
195+
"Reconfigure a resource", uri, json_data, warnings=warnings
196+
)
179197

180198
def update(
181199
isamAppliance,
@@ -306,17 +324,22 @@ def publish(isamAppliance, server, resourceUri, check_mode=False, force=False):
306324
"""
307325
ret_obj = get(isamAppliance, server, resourceUri)
308326

309-
if force or (
310-
ret_obj["data"] != {} and (
311-
ret_obj["data"]["deployrequired"] or not ret_obj["data"]["deployed"]
312-
) and ret_obj["data"]["policies"] != []
313-
):
327+
deploy_required = False
328+
if ret_obj.get("data", {}).get("deployrequired", False) or not ret_obj.get("data", {}).get("deployed", False):
329+
deploy_required = True
330+
331+
logger.debug(f"\n\nDeploy required: {deploy_required}\n\n")
332+
333+
resource_id = ret_obj.get('data', {}).get('id', None)
334+
logger.debug(f"\n\nID: {resource_id}\n\n")
335+
# if (force or deploy_required) and ret_obj.get("data", {}).get("policies", []) != []:
336+
if (force or deploy_required) and resource_id is not None:
314337
if check_mode:
315338
return isamAppliance.create_return_object(changed=True)
316339
else:
317340
return isamAppliance.invoke_put(
318341
"Publish the policy attachments for a resource",
319-
f"{uri}/deployment/{ret_obj['data']['id']}",
342+
f"{uri}/deployment/{resource_id}",
320343
{},
321344
)
322345

test/test_aac_access_control.py

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,73 @@ def getTestData():
6868
"Description": "Permit access"
6969
}
7070
}
71+
},
72+
{
73+
"dialect": "urn:oasis:names:tc:xacml:2.0:policy:schema:os",
74+
"attributesRequired": False,
75+
"name": "Test Access Control Policy 2",
76+
"description": "Permit access",
77+
"predefined": False,
78+
"formatting": "json",
79+
"policy": {
80+
"PolicyTag": "urn:ibm:security:isam:8.0:xacml:2.0:config-policy",
81+
"PolicyName": "Test Access Control Policy 2",
82+
"PolicySet": {
83+
"Policy": [
84+
{
85+
"RuleCombiningAlgId": "urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable",
86+
"Rule": {
87+
"Condition": {
88+
"Apply": [
89+
{
90+
"FunctionId": "urn:oasis:names:tc:xacml:1.0:function:and",
91+
"Apply": [
92+
{
93+
"FunctionId": "urn:oasis:names:tc:xacml:1.0:function:any-of-any",
94+
"Function": {
95+
"FunctionId": "urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal"
96+
},
97+
"Apply": [
98+
{
99+
"FunctionId": "urn:oasis:names:tc:xacml:1.0:function:integer-bag",
100+
"AttributeValue": {
101+
"DataType": "http://www.w3.org/2001/XMLSchema#integer",
102+
"content": 50
103+
}
104+
}
105+
],
106+
"SubjectAttributeDesignator": [
107+
{
108+
"Issuer": "urn:ibm:security:issuer:RiskCalculator",
109+
"AttributeId": "urn:ibm:security:subject:riskScore",
110+
"MustBePresent": True,
111+
"DataType": "http://www.w3.org/2001/XMLSchema#integer"
112+
}
113+
]
114+
}
115+
]
116+
}
117+
]
118+
},
119+
"RuleId": "urn:ibm:security:rule:0",
120+
"Effect": "Deny"
121+
},
122+
"PolicyId": "urn:ibm:security:rule-container:0"
123+
}
124+
],
125+
"PolicyCombiningAlgId": "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable",
126+
"Description": "Deny access"
127+
}
128+
}
71129
}
72130
]
73131
return testdata
74132

75133

76134
def getPolicyAttachmentData():
77135
testdata = [
78-
{"server": "default",
79-
"resourceUri": "/register_mobile.html",
136+
{"server": "isva11kvm-default",
137+
"resourceUri": "/molecule.html",
80138
"policyCombiningAlgorithm": "denyOverrides",
81139
"policies": [
82140
{"name": "Test Access Control Policy",
@@ -86,8 +144,30 @@ def getPolicyAttachmentData():
86144
"type": "reverse_proxy",
87145
"cache": 0
88146
},
147+
{"server": "isva11kvm-default",
148+
"resourceUri": "/index.html",
149+
"policyCombiningAlgorithm": "denyOverrides",
150+
"policies": [
151+
{"name": "Test Access Control Policy 2",
152+
"type": "policy"
153+
}
154+
],
155+
"type": "reverse_proxy",
156+
"cache": 0
157+
},
158+
{"server": "mobileApp",
159+
"resourceUri": "/registerApp",
160+
"policyCombiningAlgorithm": "denyOverrides",
161+
"policies": [
162+
{"name": "Test Access Control Policy",
163+
"type": "policy"
164+
}
165+
],
166+
"type": "application",
167+
"cache": 0
168+
},
89169
{"server": "mobileApp",
90-
"resourceUri": "registerApp",
170+
"resourceUri": "/somethingelseApp",
91171
"policyCombiningAlgorithm": "denyOverrides",
92172
"policies": [
93173
{"name": "Test Access Control Policy",

0 commit comments

Comments
 (0)