Security systems often struggle to balance high safety with a smooth user experience, creating frustrating bottlenecks. It is difficult to see where security measures become unnecessarily difficult for the user.
It maps out different security steps to find the most balanced path between safety and ease of use. It identifies the specific points where security becomes most difficult.
It allows for creating security flows that protect data without creating unnecessary friction for the person using them.
It was run in the sandbox and it failed. run output shows an error/traceback — the artifact does NOT run clean.
$ python3 hierarchical_mfa_path_v2.py
Traceback (most recent call last):
File "/work/hierarchical_mfa_path.py", line 53, in <module>
optimal_path = root.calculate_path()
^^^^^^^^^^^^^^^^^^^^^
File "/work/hierarchical_mfa_path.py", line 24, in calculate_path
for condition, child in self.children.items:
^^^^^^^^^^^^^^^^^^^
TypeError: 'builtin_function_or_method' object is not iterableNo screenshot — there is nothing working to show. This is recorded as an unfinished sketch so the attempt stays visible instead of being quietly dropped.
All of it — 57 lines, one file, standard library only.
from path_analyzer import MFANode
def __init__(self, name, factor, friction=1.0, security=1.0):
self.name = name
self.factor = factor
self.friction = friction
self.security = security
self.children = {}
self.score = 0
self.path = []
def add_child(self, condition, child_node):
self.children[condition] = child_node
def calculate_path(self):
if not self.children:
self.score = self.security - self.friction * 0.3
return [self]
best_path = None
max_score = float('-inf')
for condition, child in self.children.items():
path = child.calculate_path()
total_score = (self.security - self.friction * 0.3) + sum(
n.security - n.friction * 0.3 for n in path)
if total_score > max_score:
max_score = total_score
best_path = [self] + path
self.score = max_score
return best_path
if __name__ == '__main__':
root = MFANode('Start', factor=None, friction=0, security=0)
# Level 1: Initial MFA choice
otp_node = MFANode('OTP', 'otp', friction=3, security=6)
fido_node = MFANode('FIDO', 'fido', friction=1, security=9)
sms_node = MFANode('SMS', 'sms', friction=5, security=4)
root.add_child('low_risk', otp_node)
root.add_child('medium_risk', fido_node)
root.add_child('high_risk', sms_node)
# Level 2: Subsequent authentication steps
otp_node.add_child('always', MFANode('OTP Confirm', 'otp', friction=2, security=7))
fido_node.add_child('always', MFANode('FIDO Confirm', 'fido', friction=1, security=9))
# Calculate optimal path
optimal_path = root.calculate_path()
total_security = sum(node.security for node in optimal_path)
total_friction = sum(node.friction for node in optimal_path)
print(f"Optimal Path Score: {root.score:.2f}")
print(f"Path Cost Analysis:")
print(f"Total Security: {total_security:.2f}")
print(f"Total Friction: {total_friction:.2f}\n")
for i, node in enumerate(optimal_path):
print(f"Step {i+1}: {node.name} ({node.factor}) - Security: {node.security}, Friction: {node.friction}")