Skip to content

Commit 9289e30

Browse files
authored
AAP-44925 Make auth map attr and group comparison case insensitive (#746)
1 parent 2c18ec8 commit 9289e30

File tree

3 files changed

+227
-53
lines changed

3 files changed

+227
-53
lines changed

ansible_base/authentication/utils/claims.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from django.db import IntegrityError, models
1414
from django.utils.timezone import now
1515
from django.utils.translation import gettext_lazy as _
16+
from flags.state import flag_enabled
1617
from rest_framework.serializers import DateTimeField
1718

1819
from ansible_base.authentication.models import Authenticator, AuthenticatorMap, AuthenticatorUser
@@ -178,10 +179,28 @@ def _add_rbac_role_mapping(has_permission, role_mapping, role, organization=None
178179
logger.warning(f"Role mapping is not possible, organization for team '{team}' is missing")
179180

180181

182+
def _is_case_insensitivity_enabled() -> bool:
183+
return flag_enabled("FEATURE_CASE_INSENSITIVE_AUTH_MAPS")
184+
185+
186+
def _lowercase_group_triggers(trigger_condition: dict) -> dict:
187+
"""
188+
Lowercase all group names provided to trigger
189+
"""
190+
ci_trigger_condition = {}
191+
for operator, grouplist in trigger_condition.items():
192+
ci_trigger_condition[operator] = [f"{group}".casefold() for group in grouplist]
193+
return ci_trigger_condition
194+
195+
181196
def process_groups(trigger_condition: dict, groups: list, authenticator_id: int) -> TriggerResult:
182197
"""
183198
Looks at a maps trigger for a group and users groups and determines if the trigger is defined for this user.
199+
Group DNs are compared case-insensitively when FEATURE_CASE_INSENSITIVE_AUTH_MAPS enabled.
184200
"""
201+
if _is_case_insensitivity_enabled():
202+
groups = [f"{group}".casefold() for group in groups]
203+
trigger_condition = _lowercase_group_triggers(trigger_condition)
185204

186205
invalid_conditions = set(trigger_condition.keys()) - set(TRIGGER_DEFINITION['groups']['keys'].keys())
187206
if invalid_conditions:
@@ -218,10 +237,35 @@ def has_access_with_join(current_access: Optional[bool], new_access: bool, condi
218237
return current_access and new_access
219238

220239

240+
def _lowercase_attr_triggers(trigger_condition: dict) -> dict:
241+
"""
242+
Lower case all keys (attribute names) and contained attribute values
243+
"""
244+
ci_trigger_condition = {}
245+
for attr, condition in trigger_condition.items():
246+
if isinstance(condition, str):
247+
updated_condition = condition.casefold()
248+
elif isinstance(condition, dict):
249+
if not condition: # empty dict
250+
updated_condition = {}
251+
for operator, value in condition.items():
252+
updated_condition = {operator: value.casefold()}
253+
else:
254+
updated_condition = condition
255+
256+
ci_trigger_condition[attr.casefold()] = updated_condition # join_condition
257+
return ci_trigger_condition
258+
259+
221260
def process_user_attributes(trigger_condition: dict, attributes: dict, authenticator_id: int) -> TriggerResult:
222261
"""
223262
Looks at a maps trigger for an attribute and the users attributes and determines if the trigger is defined for this user.
263+
Attribute names are compared case-insensitively.
224264
"""
265+
if _is_case_insensitivity_enabled():
266+
attributes = {f"{k}".casefold(): v for k, v in attributes.items()}
267+
trigger_condition = _lowercase_attr_triggers(trigger_condition)
268+
225269
has_access = None
226270
join_condition = trigger_condition.get('join_condition', 'or')
227271
if join_condition not in TRIGGER_DEFINITION['attributes']['keys']['join_condition']['choices']:
@@ -265,7 +309,7 @@ def process_user_attributes(trigger_condition: dict, attributes: dict, authentic
265309
for a_user_value in user_value:
266310
# We are going to do mostly string comparisons, so convert the attribute to a
267311
# string just in case it came back as an int or something funky
268-
a_user_value = f"{a_user_value}"
312+
a_user_value = f"{a_user_value}".casefold() if _is_case_insensitivity_enabled() else f"{a_user_value}"
269313

270314
# Check for any of the valid conditions
271315
if "equals" in trigger_condition[attribute]:

test_app/defaults.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,10 @@
230230
"value": True,
231231
},
232232
],
233+
"FEATURE_CASE_INSENSITIVE_AUTH_MAPS": [
234+
{
235+
"condition": "boolean",
236+
"value": False,
237+
},
238+
],
233239
}

0 commit comments

Comments
 (0)