Description
When using authenticator maps with attribute-based triggers, attributes that are lists are currently evaluated element by element and combined using the global join_condition. This produces unexpected results when the join condition is and.
Steps to Reproduce
Raw attribute data:
2025-08-26 14:17:15,287 DEBUG 21d8a01d-1fe8-4527-bb44-2e75329fd9b4 ansible_base.authentication.utils.claims aapadmA100's attrs: {
'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
'cn': ['aapadmA100'],
'sn': ['A100'],
'uid': ['aapadmA100'],
'userpassword': ['{SSHA}0idZBuDtewExj/0pcgLisBDHUr5Ih/tg'],
'employeetype': ['developer', 'executor'],
'auth_time': '2025-08-26T14:17:15.284587Z'
}
-
Configure a user with attributes:
cn: ['aapadmA100']
employeetype: ['developer', 'executor']
-
Configure an authenticator map with trigger condition:
if 'aapadm' in cn and 'developer' in employeetype
-
Authenticate the user.
Expected Behavior
The condition should evaluate to true, because:
'aapadm' in ['aapadmA100'] → True
'developer' in ['developer', 'executor'] → True
Therefore, the overall expression should succeed.
Actual Behavior
In _process_user_value, list attributes are expanded and each element is evaluated individually.
Because has_access_with_join(..., join_condition) is applied inside the loop, the global join_condition (and/or) is incorrectly applied across list elements, not just across attributes.
Relevant code excerpt:
evaluate_fn = operators[operator]
for a_user_value in user_value:
user_str = f"{a_user_value}".casefold() if _is_case_insensitivity_enabled() else f"{a_user_value}"
result = evaluate_fn(user_str, trigger_value)
# <-- Problem: join_condition applied here for each element -->
has_access = has_access_with_join(has_access, result, join_condition)
header = f"Attr [{attribute}] value [{user_str}]"
message = _get_operator_messages(operator, result)
_prefixed_debug(map_id, tracking_id, f"{header} {message} [{trigger_value}], {_result_suffix(result)}")
return has_access
Evaluation steps:
-
For cn:
_evaluate_contains("aapadmA100", "aapadm")
# → "aapadm" in "aapadmA100" → True
has_access = True
-
For employeetype:
_evaluate_contains("developer", "developer")
# → "developer" in "developer" → True
has_access = has_access_with_join(True, True, "and") → True
_evaluate_contains("executor", "developer")
# → "developer" in "executor" → False
has_access = has_access_with_join(True, False, "and") → False
Final result: False, so the map is skipped/denied, even though the user clearly has "developer" in their employeetype.
Impact
Users with multi-valued attributes cannot be matched correctly when join_condition = 'and'.
This breaks common scenarios such as matching on employeetype or other attributes that often contain multiple values.
Suggestion
List attributes should be evaluated with any(...) semantics: if any element of the list matches, the condition for that attribute should be considered true.
Only after reducing each attribute’s evaluation to a single boolean should the global join_condition (and / or) be applied across attributes.
Description
When using authenticator maps with attribute-based triggers, attributes that are lists are currently evaluated element by element and combined using the global
join_condition. This produces unexpected results when the join condition isand.Steps to Reproduce
Raw attribute data:
Configure a user with attributes:
Configure an authenticator map with trigger condition:
if 'aapadm' in cn and 'developer' in employeetypeAuthenticate the user.
Expected Behavior
The condition should evaluate to true, because:
Therefore, the overall expression should succeed.
Actual Behavior
In
_process_user_value, list attributes are expanded and each element is evaluated individually.Because
has_access_with_join(..., join_condition)is applied inside the loop, the globaljoin_condition(and/or) is incorrectly applied across list elements, not just across attributes.Relevant code excerpt:
Evaluation steps:
For
cn:For
employeetype:Final result: False, so the map is skipped/denied, even though the user clearly has
"developer"in theiremployeetype.Impact
Users with multi-valued attributes cannot be matched correctly when
join_condition = 'and'.This breaks common scenarios such as matching on
employeetypeor other attributes that often contain multiple values.Suggestion
List attributes should be evaluated with
any(...)semantics: if any element of the list matches, the condition for that attribute should be considered true.Only after reducing each attribute’s evaluation to a single boolean should the global
join_condition(and/or) be applied across attributes.